有了Python线程的基础概念Python多线程–(1)之基本概念
在python中应用线程,threading模块的了解Python多线程–(2)之threading模块
以及多线程编程中最重要的一方面–同步 Python多线程–(3)同步
在上一篇同步举的例子中,我们模拟了向资源池中填入和消耗资源这个过程,填入和消耗的时间都是不确定的,其实我们用信号量已经实现了线程间的通信–在表示共享资源的数量上。不过python还给我们提供了queue模块(Python 2.x版本中为Queue),它提供了线程间的通信机制,可以让线程之间可以分享数据。
具体来说,实现的方式也是和很简单的,可以理解为创建了一个公共可以访问的队列,线程都可以访问它。具体的queue模块有的一些属性如下:
queue模块中的类:
- Queue(maxsize=0):创建一个先入先出的队列,最大值可以限制队列的空间,如果没有限定则为无限值。
- LifoQueue(maxsize=0):创建一个先入后出的队列,也就是类似栈的东西。最大值可以限制队列的空间,如果没有限定则为无限值。
- PriorQueue(maxsize=0):创建一个优先级的队列,最大值可以限制队列的空间,如果没有限定则为无限值。
异常:
- Empty():对列为空的时候调用get*()方法抛出异常
- Full():队列满时调用put*()方法抛出异常
queue对象方法:
- qsize():返回队列大小,不过其他线程可能改变队列大小,这个值不准确。
- empty():判断队列是为空,布尔值空为True,否则Flase。
- full():判断队列是否满,布尔值满为True,否则为Flase。
- put(item, block=True, timeout=None):把item放入队列中,block=True,timeout=None,则会等待直到有可用空间,timeout有值则最多阻塞多少秒。block=Flase就会抛出Empty异常。
- put_nowait(item)同put(item,Flase)。
- get(block=True,timeout=None):从队列中取得元素,block=True则阻塞到有可用元素
- get_nowait():同get(Flase)。
- task_done():用于表示队列中某个元素执行完成,和下一个方法join()一起配合使用
- join():在队列中所有元素执行完前并调用上一个task_done()之前保持阻塞。
之前的信号量例子,改用queue来进行资源的共享
from random import randint
from queue import Queue
from time import sleep
from test_8_25.mythread import MyThread
def write_queue(queue):
# 添加队列中元素行为
print('Producing object for queue...', queue.put('xxx', 1))
print('Size now', queue.qsize())
def read_queue(queue):
#消耗队列中元素行为
queue.get(1)
print('Consumed object from queue...')
print('Size now', queue.qsize())
def writer(queue, loops):
#随机向队列中添加随机个数的元素
for i in range(loops):
write_queue(queue)
sleep(randint(1, 3))
def reader(queue, loops):
# 随机消耗队列中随机个数的元素
for i in range(loops):
read_queue(queue)
sleep(randint(2,5))#等待时间比writer常,尽量避免队列在消耗时为空
funcs = [writer, reader]
nfuncs = range(len(funcs))
def main():
nloops =randint(2,5)#随机产生线程数
q = Queue(32) #获得共享队列
threads = [] #线程列表
for i in nfuncs: #生成所有的线程列表
t = MyThread(funcs[i], (q, nloops), funcs[i].__name__)
threads.append(t)
for i in nfuncs:
threads[i].start() #开启所有的线程
for i in nfuncs:
threads[i].join() #这里需要将线程挂起,否则主线程会线程结束前打印“all done”
# 或者你也可以使用atexit()来限制在主线程退出时在打印
print("All done.")
if __name__ == '__main__':
main()
结果实例(结果随机不尽相同):
Starting writer at: Sat Aug 26 19:27:42 2017
Producing object for queue... None
Size now 1
Starting reader at: Sat Aug 26 19:27:42 2017
Consumed object from queue...
Size now 0
Producing object for queue... None
Size now 1
Producing object for queue... None
Size now 2
Consumed object from queue...
Size now 1
Consumed object from queue...
Size now 0
Producing object for queue... None
Size now 1
Consumed object from queue...
Size now 0
writer finished at: Sat Aug 26 19:27:53 2017
reader finished at: Sat Aug 26 19:27:53 2017
All done.