Python3入门之线程queue
queue模块介绍
queue模块定义了下面的类和异常:
class queue.Queue(maxsize=0)
import queue import time q = queue.Queue() #FIFO队列先进先出 q.put(2) q.put(1) q.put(3) while not q.empty(): next_item = q.get() print(next_item) time.sleep(1) 执行结果: 2 1 3
class queue.LifoQueue(maxsize=0)
import queue import time q = queue.LifoQueue() #LIFO队列后进先出 q.put(2) q.put(1) q.put(3) while not q.empty(): next_item = q.get() print(next_item) time.sleep(1) 执行结果: 3 1 2
class queue.LifoQueue(maxsize=0)
from queue import PriorityQueue import time q = PriorityQueue() q.put((2, 'code')) q.put((1, 'eat')) q.put((3, 'sleep')) while not q.empty(): next_item = q.get() print(next_item) time.sleep(3) 执行结果: (1, 'eat') (2, 'code') (3, 'sleep')
exception queue.Empty
exception queue.Full
Queue对象(Queue、LifoQueue或者PriorityQueue)提供了以下方法:
Queue.qsize()
返回队列的近似大小。注意,qsize() > 0并不能保证接下来的get()方法不被阻塞;同样,qsize() < maxsize也不能保证put()将不被阻塞。import queue import time q = queue.Queue() q.put(2) q.put(1) q.put(3) q.put('python') print('queue long:%s'%q.qsize()) 执行结果: queue long:4
Queue.empty()
如果队列是空的,则返回True,否则False。如果empty()返回True,并不能保证接下来的put()调用将不被阻塞。类似的,empty()返回False也不能保证接下来的get()调用将不被阻塞。
import queue q = queue.Queue() que = queue.Queue() q.put(2) q.put(1) q.put(3) q.put('python') print('q is empty? :%s'%q.empty()) print('que is empty? :%s'%que.empty()) 执行结果: q is empty? :False #队列不为空则返回False que is empty? :True #队列未空则返回True
Queue.full()
如果队列满则返回True,否则返回False。如果full()返回True,并不能保证接下来的get()调用将不被阻塞。类似的,full()返回False也不能保证接下来的put()调用将不被阻塞。
import queue q = queue.Queue(maxsize=4) que = queue.Queue() q.put(2) q.put(1) q.put(3) q.put('python') print('q is full? :%s'%q.full()) print('que is full? :%s'%que.full()) 执行结果: q is full? :True que is full? :False
Queue.put(item, block=True, timeout=None)
放item到队列中。如果block是True,且timeout是None,该方法将一直等待直到有队列有空余空间(默认block=True,timeout=None)。如果timeout是一个正整数,该方法则最多阻塞timeout秒并抛出Full异常。如果block是False并且队列满,则直接抛出Full异常(这时timeout将被忽略)。
block为True
import queue import time q = queue.Queue(maxsize=2) #将q队列填满 q.put('python') q.put('linux') print(time.ctime()) #打印当前时间 try: #捕获queue.Full异常 #q.put('shell', timeout=3) #默认block=True #q.put('shell', True, timeout=3) #可以省略block=;直接写True;timeout=可以省略直接写3 q.put('shell', block=True, timeout=3) #q队列已满,再次将数据放入q中,将阻塞3s后抛出异常queue.Full except queue.Full: print('queue is full!') print(time.ctime()) #打印当前时间,可看出q队列阻塞时长 执行结果: Fri Nov 3 15:06:43 2017 queue is full! Fri Nov 3 15:06:46 2017
block为False
import queue import time q = queue.Queue(maxsize=2) #将q队列填满 q.put('python') q.put('linux') print(time.ctime()) #打印当前时间 try: #捕获queue.Full异常 q.put('shell', False, timeout=3) #block为False时,timeout失效会立即抛出queue.Full异常;故timeout选项可以省略不写 except queue.Full: print('queue is full!') print(time.ctime()) #打印当前时间,可看出q队列阻塞时长 执行结果: Fri Nov 3 15:12:21 2017 queue is full! Fri Nov 3 15:12:21 2017
Queue.put_nowait(item)
等价于put(item, False)。
Queue.get(block=True, timeout=None)
从队列中移除被返回一个条目。如果block是True并且timeout是None(默认block=True,timeout=None),该方法将阻塞直到队列中有条目可用。如果timeout是正整数,该方法将最多阻塞timeout秒并抛出Empty异常。如果block是False并且队列为空,则直接抛出Empty异常(这时timeout将被忽略)。
block为True
import queue import time q = queue.Queue(maxsize=2) #当前q队列填为空 print(time.ctime()) #打印当前时间 try: #捕获queue.Empty异常 q.get(True, 5) #Queue.get()获取数据阻塞5s except queue.Empty: print('queue is empty!') print(time.ctime()) #打印当前时间,可看出q队列阻塞时长 执行结果: Fri Nov 3 15:34:46 2017 queue is empty! Fri Nov 3 15:34:51 2017
block为False
import queue import time q = queue.Queue(maxsize=2) #当前q队列填为空 print(time.ctime()) #打印当前时间 try: #捕获queue.Empty异常 #q.get(False, 5) #Queue.get()获取数据阻塞5s,block=/timeout=可以省略;block=False时timeout可以省略 q.get(False) except queue.Empty: print('queue is empty!') print(time.ctime()) #打印当前时间,可看出q队列阻塞时长 执行结果: Fri Nov 3 15:38:23 2017 queue is empty! Fri Nov 3 15:38:23 2017
Queue.get_nowait()
等价于get(False)。
Queue.task_done()
表示一个先前的队列中的任务完成了。被队列消费者线程使用。对于每个get()获取到的任务,接下来的task_done()的调用告诉队列该任务的处理已经完成。
如果join()调用正在阻塞,当队列中所有的条目被处理后它将恢复执行(意味着task_done()调用将被放入队列中的每个条目接收到)。
如果调用次数超过了队列中放置的条目数目,将抛出ValueError异常。
Queue.join()
当一个条目被增加到队列时,未完成任务的计数将增加。当一个消费者线程调用task_done()时,未完成任务的计数将减少。当未完成任务的计数减少到0时,join()解锁。
#!/usr/bin/env python3 import queue import time import subprocess import threading q = queue.Queue() hosts = ['192.168.1.68', '192.168.1.118', '192.168.1.101', '192.168.1.250', '192.168.1.133'] def run(): while True: #防止线程少于len(hosts)时卡死,不用while循环线程数少时就会导致队列数据无法全部取完,就会造成queue.join()一直阻塞状态 host = q.get() if host == '192.168.1.118': #如果ip等于192.168.1.118就休眠10S,用于判读queue.join()是否阻塞直到queue.task_doen()通知后接触阻塞 time.sleep(10) print('host ip is:%s'% host) q.task_done() #当前线程任务完成 def main(): for i in range(10): t = threading.Thread(target=run) t.setDaemon(True) t.start() for item in hosts: q.put(item) q.join() #阻塞直至所有线程queue.task_done()返回 start = time.time() main() print("Elapsed Time: %s" % (time.time() - start)) 执行结果: host ip is:192.168.88.68 host ip is:192.168.68.101 host ip is:192.168.66.250 host ip is:192.168.88.133 host ip is:192.168.88.118 Elapsed Time: 10.013836145401001 #由于192.168.1.118大约阻塞了10S
***********************************************************
学习永远不晚。——高尔基
***********************************************************