zoukankan      html  css  js  c++  java
  • 线程中的队列(queue)

    队列的类型和常用方法

    队列是一种数据结构,它类似于列表。但列表是线程不安全的,而队列是线程安全的。

    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

  • 相关阅读:
    Python 练习册,每天一个小程序----第0000题
    CMDB系统原创开发
    203.pycharm连接远程终端
    202. 菜鸟学习k8s安装1
    (高并发)防止重复点击,屏蔽多次无效请求的解决方案(优惠劵被重复领取,恶意撸羊毛)
    SSM批量插入和修改实现实例
    java服务器访问其他服务器工具类编写
    递归实例,欢迎大家修改优化
    SpringJDBC
    Spring入门
  • 原文地址:https://www.cnblogs.com/guyexiangyun/p/10592620.html
Copyright © 2011-2022 走看看