队列的类型和常用方法
队列是一种数据结构,它类似于列表。但列表是线程不安全的,而队列是线程安全的。
python的queue(python3,python2为Queue)提供了3种队列:
- Queue:先进先出型(First In First Out)。
- LifoQueue:后进先出型(Last In First Out)。
- PriorityQueue:优先级型,为队列中的元素自定义优先级,按照优先级获取元素。
每种队列的构造方法都有一个maxsize的属性,默认为0,该属性用来指定队列存放的最大元素个数。如果为0或小于0,则队列是无限长的。
队列中的方法:
- q.put(10):将某个元素放到队列中。该方法中的参数item(即要存放的元素)是必须指定的;
- 参数block=True,该参数是否采取阻塞的方式向队列中放置元素。如果block=True,则put方法会在队列已经满了的情况(没有空余位置)下阻塞,直到队列中空出位置后再将元素放置到队列中;如果block=False,不论队列是否有空余位置都会尝试将元素放到队列中,当队列已满时会抛出“满队列异常(Full exception)”。q.put_nowait()方法相当于q.put(block=False)。
- 参数timeout=None,当该参数被设置为x(大于或等于0)时,put方法最多会阻塞x秒,之后尝试向队列中存放元素,如果队列已满,则会抛出Full exception。
- q.get():对于Queue创建的队列来说,该方法会从队列头部获取并删除一个元素(最先进入队列的元素)。该方法同样也有可选参数block=True。默认情况下(True),该方法会在队列为空时阻塞,直到有元素被放入到队列中;当block=False时,该方法不会阻塞,如果队列为空,则会抛出"空队列异常(Empty exception)“。q.get_nowait()方法相当于q.get(block=False)。
- q.task_done():在完成某项队列操作后向队列发送一个信号。
- 判断队列属性的方法有:
- q.qsize():返回队列的长度;
- q.empty():如果队列为空,返回True,否则返回False。
- q.full():如果队列满了,返回True,否则返回False。
示例1:先进先出型,使用多个线程从同一队列中取出元素
1 import threading, time, queue 2 3 class MyThread(threading.Thread): 4 5 def run(self): 6 7 while True: 8 if q.qsize() > 0: 9 item = q.get() # 从队列中取出元素 10 print("%s::取出的元素---->%s at %s" % (self.name, item, time.ctime())) 11 time.sleep(2) 12 else: 13 print("队列已空,无法取出元素") 14 break 15 16 17 if __name__ == '__main__': 18 19 q = queue.Queue() 20 21 for i in range(10): 22 q.put(i) # 将0-9的数字放到队列q中 23 24 threads = [] 25 26 for i in range(3): 27 threads.append(MyThread()) 28 29 for t in threads: 30 t.start() 31 32 for t in threads: 33 t.join() 34 35 print("main thread ending....")
打印结果如下:
Thread-1::取出的元素---->0 at Tue Mar 26 16:33:41 2019 Thread-2::取出的元素---->1 at Tue Mar 26 16:33:41 2019 Thread-3::取出的元素---->2 at Tue Mar 26 16:33:41 2019 Thread-2::取出的元素---->3 at Tue Mar 26 16:33:43 2019 Thread-1::取出的元素---->4 at Tue Mar 26 16:33:43 2019 Thread-3::取出的元素---->5 at Tue Mar 26 16:33:43 2019 Thread-3::取出的元素---->6 at Tue Mar 26 16:33:45 2019 Thread-1::取出的元素---->7 at Tue Mar 26 16:33:45 2019 Thread-2::取出的元素---->8 at Tue Mar 26 16:33:45 2019 Thread-2::取出的元素---->9 at Tue Mar 26 16:33:47 2019 队列已空,无法取出元素 队列已空,无法取出元素 队列已空,无法取出元素 main thread ending.... ***Repl Closed***
可以看到,3个线程循环的从队列中取出元素,元素获取的顺序与放入队列的顺序一致。
示例2:LiFoQueue(后进先出队列)与PriorityQueue(优先级队列)
1 import queue 2 3 def my_LiFo_queue(): 4 q = queue.LifoQueue() 5 for i in range(5): 6 q.put(i) 7 8 while not q.empty(): 9 print("LiFo queue -->", q.get()) 10 11 def my_proirity_queue(): 12 q = queue.PriorityQueue() 13 q.put(10) 14 q.put(7) 15 q.put(3) 16 q.put(1) 17 18 while not q.empty(): 19 print("proirity queue-->", q.get()) 20 21 my_LiFo_queue() 22 23 my_proirity_queue()
打印结果如下所示:
LiFo queue --> 4 LiFo queue --> 3 LiFo queue --> 2 LiFo queue --> 1 LiFo queue --> 0 proirity queue--> 1 proirity queue--> 3 proirity queue--> 7 proirity queue--> 10 Process finished with exit code 0
对于PriorityQueue,我们可以自定义它的内部比较方法,为每个元素指定优先级后get()方法就会根据优先级来获取队列中的元素。
1 import queue 2 3 4 class Skill(object): 5 def __init__(self, priority, description): 6 self.priority = priority # 优先级参照 7 self.description = description 8 9 def __lt__(self, other): # 重新定义实例间的比较规则(<) 10 return self.priority < other.priority 11 12 def __str__(self): # 重新定义该类实例的打印信息 13 return "(%s, '%s')" % (self.priority, self.description) 14 15 16 def PriorityQueue_class(): 17 q = queue.PriorityQueue() 18 q.put(Skill(7, 'proficient7')) 19 q.put(Skill(5, 'proficient5')) 20 q.put(Skill(6, 'proficient6')) 21 q.put(Skill(10, 'expert')) 22 q.put(Skill(1, 'novice')) 23 print('end') 24 while not q.empty(): 25 print(q.get()) 26 27 28 PriorityQueue_class()
打印结果如下所示:
end (1, 'novice') (5, 'proficient5') (6, 'proficient6') (7, 'proficient7') (10, 'expert') Process finished with exit code 0
可见,get方法是按照优先级从低到高的顺序依次取出元素的。
参考:
https://www.cnblogs.com/itogo/p/5635629.html
https://www.cnblogs.com/saolv/p/9502124.html