Python-Queue 入门


  • Queue 简介

  • Queue 叫队列,是数据结构中的一种,基本上所有成熟的编程语言都内置了对 Queue 的支持。
  • Python 中的 Queue 模块实现了多生产者和多消费者模型,当需要在多线程编程中非常实用。而且该模块中的 Queue 类实现了锁原语,不需要再考虑多线程安全问题
  • 该模块内置了三种类型的 Queue,分别是 class queue.Queue(maxsize=0)class queue.LifoQueue(maxsize=0) 和 class queue.PriorityQueue(maxsize=0)。它们三个的区别仅仅是取出时的顺序不一致而已。
  • Queue 是一个 FIFO 队列,任务按照添加的顺序被取出。

    LifoQueue 是一个 LIFO 队列,类似堆栈,后添加的任务先被取出。

    PriorityQueue 是一个优先级队列,队列里面的任务按照优先级排序,优先级高的先被取出。

  • Queue 常用操作

  • 类和异常

  • 1 class queue.Queue(maxsize=0)
    2 class queue.LifoQueue(maxsize=0)
    3 class queue.PriorityQueue(maxsize=0)

     

  • 如你所见,就是上面所说的三种不同类型的内置队列,其中 maxsize 是个整数,用于设置可以放入队列中的任务数的上限。当达到这个大小的时候,插入操作将阻塞至队列中的任务被消费掉。如果 maxsize 小于等于零,则队列尺寸为无限大。
  • 1 exception queue.Empty
    2 # 对空的 Queue 对象调用非阻塞的 get() (or get_nowait()) 时,会引发该异常。
    3 
    4 exception queue.Full
    5 # 对满的 Queue 对象调用非阻塞的 put() (or put_nowait()) 时,会引发该异常。

     

  • 常用操作

  • 添加任务

  • 向队列中添加任务,直接调用 put() 函数即可
  • 1 import queue
    2 >>> q = queue.Queue(maxsize=1)
    3 >>> q.put(100)

     

  • put() 函数完整的函数签名如下 Queue.put(item, block=True, timeout=None),如你所见,该函数有两个可选参数。
  • 默认情况下,在队列满时,该函数会一直阻塞,直到队列中有空余的位置可以添加任务为止。如果 timeout 是正数,则最多阻塞 timeout 秒,如果这段时间内还没有空余的位置出来,则会引发 Full 异常。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.put(100)
     4 >>> q.put(100,True,2)
     5 Traceback (most recent call last):
     6   File "<stdin>", line 1, in <module>
     7   File "E:\Python37-32\lib\queue.py", line 147, in put
     8     raise Full
     9 queue.Full # 创建一个容量为 1 的队列,2 秒内没有位置添加任务则引发 Full 异常
    10 >>> q.put(100) # 该方法会一直阻塞

     

  • 当 block 为 false 时,timeout 参数将失效。同时如果队列中没有空余的位置可添加任务则会引发 Full 异常,否则会直接把任务放入队列并返回,不会阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.put(100)
     4 >>> q.put(100,False,2)
     5 Traceback (most recent call last):
     6   File "<stdin>", line 1, in <module>
     7   File "E:\Python37-32\lib\queue.py", line 136, in put
     8     raise Full
     9 queue.Full
    10 # 创建一个容量为 1 的队列,在第二次放入任务时指定为非阻塞模式,则会立刻引发 Full 异常

     

  • 另外,还可以通过 Queue.put_nowait(item) 来添加任务,相当于 Queue.put(item, False),不再赘述。同样,在队列满时,该操作会引发 Full 异常。
  • 获取任务

  • 从队列中获取任务,直接调用 get() 函数即可
  • 1 >>> import queue
    2 >>> q = queue.Queue()
    3 >>> q.put(100)
    4 >>> q.get()
    5 100

     

  •  put() 函数一样,get() 函数也有两个可选参数,完整签名如下 Queue.get(block=True, timeout=None)
  • 默认情况下,当队列空时调用该函数会一直阻塞,直到队列中有任务可获取为止。如果 timeout 是正数,则最多阻塞 timeout 秒,如果这段时间内还没有任务可获取,则会引发Empty 异常。
  •  1 >>> import queue
     2 >>> q = queue.Queue()
     3 >>> q.put(100)
     4 >>> q.get()
     5 100
     6 >>> q.get(True,2)
     7 Traceback (most recent call last):
     8   File "<stdin>", line 1, in <module>
     9   File "E:\Python37-32\lib\queue.py", line 178, in get
    10     raise Empty
    11 _queue.Empty # 2 秒钟内没有任务可获取则引发 Empty 异常
    12 >>> q.get() # 该方法会一直阻塞

     

  • 当 block 为 false 时,timeout 参数将失效。同时如果队列中没有任务可获取则会立刻引发 Empty 异常,否则会直接获取一个任务并返回,不会阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue()
     3 >>> q.put(100)
     4 >>> q.get()
     5 100
     6 >>> q.get(False,2)
     7 Traceback (most recent call last):
     8   File "<stdin>", line 1, in <module>
     9   File "E:\Python37-32\lib\queue.py", line 167, in get
    10     raise Empty
    11 _queue.Empty 
    12 # 指定为非阻塞模式,队列为空则立即引发 Empty 异常

     

  • 另外,还可以通过 Queue.get_nowait() 来获取任务,相当于 Queue.get(False),不再赘述。同样,在队列为空时,该操作会引发 Empty 异常。
  • 其他常用方法

  • 获取队列大小

  • 1 >>> import queue
    2 >>> q = queue.Queue()
    3 >>> q.put(100)
    4 >>> q.put(200)
    5 >>> q.qsize()
    6 2

     

  • 判断队列是否空

  • 如果队列为空,返回 True ,否则返回 False 。如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。
  • 判断队列是否满

  • 如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。
  •  1 >>> import queue
     2 >>> q = queue.Queue(maxsize=1)
     3 >>> q.empty()
     4 True
     5 >>> q.full()
     6 False
     7 >>> q.put(100)
     8 >>> q.empty()
     9 False
    10 >>> q.full()
    11 True

     

  • 队列对比

  • FIFO 队列

  • queue.Queue() 是 FIFO 队列,出队顺序跟入队顺序是一致的。
  • 1 import queue
    2 q = queue.Queue()
    3 for index in range(10):
    4     q.put(index)
    5 while not q.empty():
    6     print(q.get(), end=", ")
    7 ## 输出结果如下
    8 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

     

  • LIFO 队列

  • queue.LifoQueue() 是 LIFO 队列,出队顺序跟入队顺序是完全相反的,类似于栈。
  • import queue
    q = queue.LifoQueue() # 创建一个 LIFO 队列
    for index in range(10):
        q.put(index)
    while not q.empty():
        print(q.get(), end=", ")
    ## 输出结果如下
    9, 8, 7, 6, 5, 4, 3, 2, 1, 0,

     

  • 优先级队列

    优先级队列中的任务顺序跟放入时的顺序是无关的,而是按照任务的大小来排序,最小值先被取出。那任务比较大小的规则是怎么样的呢。

  • 如果是内置类型,比如数值或者字符串,则按照自然顺序来比较排序。

  • import queue
    q = queue.PriorityQueue()
    for index in range(10,0,-1):
        q.put(index)
    while not q.empty():
        print(q.get(), end=", ")
    ## 输出结果如下
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10,

     

  • 如果是列表或者元祖,则先比较第一个元素,然后比较第二个,以此类推,直到比较出结果

  • import queue
    q = queue.PriorityQueue()
    q.put(["d","b"])
    q.put(["c","b"])
    while not q.empty():
        print(q.get(), end=", ")
    ## 输出结果如下
    ['c', 'b'], ['d', 'b'],

     

  • 注意,因为列表的比较对规则是按照下标顺序来比较的,所以在没有比较出大小之前 ,队列中所有列表对应下标位置的元素类型要一致。
  • 好比 [2,1] 和 ["1","b"] 因为第一个位置的元素类型不一样,所以是没有办法比较大小的,所以也就放入不了优先级队列。
  • 然而对于 [2,1] 和 [1,"b"] 来说即使第二个元素的类型不一致也是可以放入优先级队列的,因为只需要比较第一个位置元素的大小就可以比较出结果了,就不需要比较第二个位置元素的大小了。
  • 但是对于 [2,1] 和 1[2,"b"] 来说,则同样不可以放入优先级队列,因为需要比较第二个位置的元素才可以比较出结果,然而第二个位置的元素类型是不一致的,无法比较大小。
  • 综上,也就是说,直到在比较出结果之前,对应下标位置的元素类型都是需要一致的
  • 如果是自定义类型,需要实现 __lt__ 比较函数

  • 下面我们自定义一个动物类型,希望按照年龄大小来做优先级排序。年龄越小优先级越高。
  • import queue
    q = queue.PriorityQueue()
    
    class Animal:
        def __init__(self, age, name):
            self.age = age
            self.name = name
        def __lt__(self, other): # 实现 < 操作
            return self.age < other.age # 如果将 < 变成 > 则相当于逆序
    
    q.put(Animal(3,"cat"))
    q.put(Animal(2,"dog"))
    
    while not q.empty():
        animal = q.get()
        print(animal.name, animal.age, end=", ")
    ## 输出结果如下
    dog 2, cat 3,

     


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM