Python的线程07 带你验收一款线程安全的队列

Posted 雷学委

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python的线程07 带你验收一款线程安全的队列相关的知识,希望对你有一定的参考价值。

正式的Python专栏第45篇,同学站住,别错过这个从0开始的文章!

前面多篇文章详细讲解了线程和线程安全,以及一些程序多线程错误下的,线程安全改造。

是否有一种神器,解决线程/并发的问题呢?

有,它就是队列(Queue)

什么是队列?

像排队一样,从头到尾排成一排,还可以有人继续往后排队,这就是队列。

这里学委想说的是Queue这个类, 它是queue这个内置模块内的一个类。

import queue
q = queue.Queue(5) #可以传入参数指定队列大小
queue.Queue()# 不传或者给0或者<0的数字则创建一个无限长度的队列

它提供了很多函数,下面几个函数,我们使用的比较多:

  • get: 获取并移除队头元素,就是出队
  • put: 往队列末尾加入元素,也就是后来者排队
  • qsize: 获取队列的长度
  • empty: 队列空了,没有人在排了
  • full: 队列满了。

看着比较枯燥,学委画了下图展示:

这个队列put了3次,依次放入:持续学习,持续开发,我雷学委。队列长度为3

队列基操 入队/出队/查队列状态

学委准备了下面的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/11/24 12:02 上午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : threadsafe_queue0.py
# @Project : hello


import queue

q = queue.Queue(5)

print("学委粉丝队列:", q)
print("空队,学委粉丝队列大小:", q.qsize())
print("空队列?", q.empty())
for i in range(5):
    q.put(i)

print("队列满了?", q.full())
print("排满了,学委粉丝队列大小:", q.qsize())

while not q.empty():
    print("粉丝 %s 出队点赞!" % q.get())
print("最后,学委粉丝队列大小:", q.qsize())

这段代码创建了一个长的为5的队列。

然后一个循环写满队列,接着再依此出队,粉丝出队点赞。

下面是运行效果:

是不是很简单。

好消息,Queue这个是一个线程安全的类

前面学委展示了几篇文章,碰到下面的代码(反复读写共享变量)结果总是出乎依赖!

amount = 100
def transfer(money):
    global amount
    for i in range(100000):
        amount += money

如果我们对队列进行反复读写,会不会出现问题呢?

不妨,写个代码验收一下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/11/24 12:02 上午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : threadsafe_queue1.py
# @Project : hello


import queue
import threading

xuewei_fans_q = queue.Queue()


def transfer(money):
    for i in range(100000):
        xuewei_fans_q.put(money)
        xuewei_fans_q.get()


# 创建4个任务重复给学委加关注/脱粉(还是希望各位编程的明日之星跟着学习,共同进步!)
t_group = []
for i in range(10):
    t = threading.Thread(target=lambda: transfer(-1))
    t_group.append(t)
    t.start()
    t = threading.Thread(target=lambda: transfer(1))
    t_group.append(t)
    t.start()
    t = threading.Thread(target=lambda: transfer(-1))
    t_group.append(t)
    t.start()
    t = threading.Thread(target=lambda: transfer(1))
    t_group.append(t)
    t.start()

for t in t_group:
    t.join()
print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
#反复对队列进行添加数据,移除数据,队列最后清零了
print("学委粉丝队列:", xuewei_fans_q.qsize())

不管运行多少次,队列(希望是黑粉队列)都为0元素。

总结

本篇学委分享了一个线程安全的队列Queue,这个非常重要!

前面花了很多篇幅讲解多线程出现的一些问题和解决,很麻烦。

但是队列Queue这个类是线程安全的,这个是经过验证的,读者朋友务必掌握牢固。

虽然展示的队列是粉丝队列,学委还是希望各位编程的明日之星跟着学习,一起共同进步!

下一篇学委将分享用队列改造转账程序,优雅的解决转账金额错误的问题。

对了,喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

以上是关于Python的线程07 带你验收一款线程安全的队列的主要内容,如果未能解决你的问题,请参考以下文章

Python 内置队列 queue快速一览

Python 内置队列 queue快速一览

Python 内置队列 queue快速一览

Python 内置队列 queue快速一览

Python 内置队列 FIFO vs FILO 队列对比展示

Python 内置队列 FIFO vs FILO 队列对比展示