Python collections.deque vs. Queue.Queue vs. multiprocessing.Queue

总体上来说,当需要在进程间通信的时候需要使用multiprocessing.Queue; 当在同一个进程当中,而需要多线程之间通信的时候,可以使用Queue.Queue;而至于collections.deque一般就是在同一个线程当中,作为一种数据结构来使用的。下面分别讲述一下它们的用法:

multiprocessing.Queue

multiprocessing提供了两种进程间通信机制,一种是我们要说的Queue,另外一种是Pipe。而实际上Queue也是通过Pipe来实现的。具体可以参考进程间通信 Queue常用methods:

  • Queue.qsize(): 返回queue中item的数量,注意这个数量并不准确, not reliable
  • Queue.empty(): return True if queue is empty, not reliable
  • Queue.full(): return True if queue is full, not reliable
  • Queue.put(item[, block[, timeout]]): block表示是否阻塞,默认为True即阻塞,如果设定了timeout,则阻塞timeout时长,如果仍然没有空余的slot,则raise Queue.full exception。如果block=False,那么就不阻塞,当queue full时,直接报Queue.full exception。
  • Queue.put_nowait(item): Equivalent to put(item, False)
  • Queue.get([block[, timeout]])
  • Queue.get_nowait(): Equivalent to get(False)

示例:

1
2
3
4
5
6
7
8
9
10
11
from multiprocessing import Process, Queue

def f(q):
q.put([42, None, 'hello'])

if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print q.get() # prints "[42, None, 'hello']"
p.join()

需要注意的是Queue不提供join()和task_done(),因此在producer process中无法确保所有的task均已经被处理, 如果需要join and task_done就需要使用multiprocessing.JoinableQueue,详情参看JoinableQueue

Queue.Queue

Queue.Queue通常用于同一个进程中的不同线程间的通信,其提供的方法与multiprocessing.Queue类似,但是多出了两个methods如下:

  • task_done(): 用于告知任务完成
  • join(): 用于等待队列中所有的任务完成。具体使用见下图 queue

collections.deque

主要用于队列这种数据结构,通过append和popleft来实现队列的FIFO机制。常用方法如下:

  • extendleft
  • appendleft
  • popleft
  • extend
  • append
  • pop 具体参考官网 示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    >>> from collections import deque
    >>> d = deque('ghi') # make a new deque with three items
    >>> for elem in d: # iterate over the deque's elements
    ... print elem.upper()
    G
    H
    I

    >>> d.append('j') # add a new entry to the right side
    >>> d.appendleft('f') # add a new entry to the left side
    >>> d # show the representation of the deque
    deque(['f', 'g', 'h', 'i', 'j'])

    >>> d.pop() # return and remove the rightmost item
    'j'
    >>> d.popleft() # return and remove the leftmost item
    'f'
    >>> list(d) # list the contents of the deque
    ['g', 'h', 'i']
    >>> d[0] # peek at leftmost item
    'g'
    >>> d[-1] # peek at rightmost item
    'i'

    >>> list(reversed(d)) # list the contents of a deque in reverse
    ['i', 'h', 'g']
    >>> 'h' in d # search the deque
    True
    >>> d.extend('jkl') # add multiple elements at once
    >>> d
    deque(['g', 'h', 'i', 'j', 'k', 'l'])
    >>> d.rotate(1) # right rotation
    >>> d
    deque(['l', 'g', 'h', 'i', 'j', 'k'])
    >>> d.rotate(-1) # left rotation
    >>> d
    deque(['g', 'h', 'i', 'j', 'k', 'l'])

    >>> deque(reversed(d)) # make a new deque in reverse order
    deque(['l', 'k', 'j', 'i', 'h', 'g'])
    >>> d.clear() # empty the deque
    >>> d.pop() # cannot pop from an empty deque
    Traceback (most recent call last):
    File "<pyshell#6>", line 1, in -toplevel-
    d.pop()
    IndexError: pop from an empty deque

    >>> d.extendleft('abc') # extendleft() reverses the input order
    >>> d
    deque(['c', 'b', 'a'])