11"""Queues"""
22
3- __all__ = ['Queue' , 'PriorityQueue' , 'LifoQueue' , 'JoinableQueue ' ,
4- 'QueueFull' , 'QueueEmpty ' ]
3+ __all__ = ['Queue' , 'PriorityQueue' , 'LifoQueue' , 'QueueFull' , 'QueueEmpty ' ,
4+ 'JoinableQueue ' ]
55
66import collections
77import heapq
@@ -49,6 +49,9 @@ def __init__(self, maxsize=0, *, loop=None):
4949 self ._getters = collections .deque ()
5050 # Pairs of (item, Future).
5151 self ._putters = collections .deque ()
52+ self ._unfinished_tasks = 0
53+ self ._finished = locks .Event (loop = self ._loop )
54+ self ._finished .set ()
5255 self ._init (maxsize )
5356
5457 def _init (self , maxsize ):
@@ -59,6 +62,8 @@ def _get(self):
5962
6063 def _put (self , item ):
6164 self ._queue .append (item )
65+ self ._unfinished_tasks += 1
66+ self ._finished .clear ()
6267
6368 def __repr__ (self ):
6469 return '<{} at {:#x} {}>' .format (
@@ -75,6 +80,8 @@ def _format(self):
7580 result += ' _getters[{}]' .format (len (self ._getters ))
7681 if self ._putters :
7782 result += ' _putters[{}]' .format (len (self ._putters ))
83+ if self ._unfinished_tasks :
84+ result += ' tasks={}' .format (self ._unfinished_tasks )
7885 return result
7986
8087 def _consume_done_getters (self ):
@@ -126,9 +133,6 @@ def put(self, item):
126133 'queue non-empty, why are getters waiting?' )
127134
128135 getter = self ._getters .popleft ()
129-
130- # Use _put and _get instead of passing item straight to getter, in
131- # case a subclass has logic that must run (e.g. JoinableQueue).
132136 self ._put (item )
133137
134138 # getter cannot be cancelled, we just removed done getters
@@ -154,9 +158,6 @@ def put_nowait(self, item):
154158 'queue non-empty, why are getters waiting?' )
155159
156160 getter = self ._getters .popleft ()
157-
158- # Use _put and _get instead of passing item straight to getter, in
159- # case a subclass has logic that must run (e.g. JoinableQueue).
160161 self ._put (item )
161162
162163 # getter cannot be cancelled, we just removed done getters
@@ -219,6 +220,38 @@ def get_nowait(self):
219220 else :
220221 raise QueueEmpty
221222
223+ def task_done (self ):
224+ """Indicate that a formerly enqueued task is complete.
225+
226+ Used by queue consumers. For each get() used to fetch a task,
227+ a subsequent call to task_done() tells the queue that the processing
228+ on the task is complete.
229+
230+ If a join() is currently blocking, it will resume when all items have
231+ been processed (meaning that a task_done() call was received for every
232+ item that had been put() into the queue).
233+
234+ Raises ValueError if called more times than there were items placed in
235+ the queue.
236+ """
237+ if self ._unfinished_tasks <= 0 :
238+ raise ValueError ('task_done() called too many times' )
239+ self ._unfinished_tasks -= 1
240+ if self ._unfinished_tasks == 0 :
241+ self ._finished .set ()
242+
243+ @coroutine
244+ def join (self ):
245+ """Block until all items in the queue have been gotten and processed.
246+
247+ The count of unfinished tasks goes up whenever an item is added to the
248+ queue. The count goes down whenever a consumer calls task_done() to
249+ indicate that the item was retrieved and all work on it is complete.
250+ When the count of unfinished tasks drops to zero, join() unblocks.
251+ """
252+ if self ._unfinished_tasks > 0 :
253+ yield from self ._finished .wait ()
254+
222255
223256class PriorityQueue (Queue ):
224257 """A subclass of Queue; retrieves entries in priority order (lowest first).
@@ -249,54 +282,5 @@ def _get(self):
249282 return self ._queue .pop ()
250283
251284
252- class JoinableQueue (Queue ):
253- """A subclass of Queue with task_done() and join() methods."""
254-
255- def __init__ (self , maxsize = 0 , * , loop = None ):
256- super ().__init__ (maxsize = maxsize , loop = loop )
257- self ._unfinished_tasks = 0
258- self ._finished = locks .Event (loop = self ._loop )
259- self ._finished .set ()
260-
261- def _format (self ):
262- result = Queue ._format (self )
263- if self ._unfinished_tasks :
264- result += ' tasks={}' .format (self ._unfinished_tasks )
265- return result
266-
267- def _put (self , item ):
268- super ()._put (item )
269- self ._unfinished_tasks += 1
270- self ._finished .clear ()
271-
272- def task_done (self ):
273- """Indicate that a formerly enqueued task is complete.
274-
275- Used by queue consumers. For each get() used to fetch a task,
276- a subsequent call to task_done() tells the queue that the processing
277- on the task is complete.
278-
279- If a join() is currently blocking, it will resume when all items have
280- been processed (meaning that a task_done() call was received for every
281- item that had been put() into the queue).
282-
283- Raises ValueError if called more times than there were items placed in
284- the queue.
285- """
286- if self ._unfinished_tasks <= 0 :
287- raise ValueError ('task_done() called too many times' )
288- self ._unfinished_tasks -= 1
289- if self ._unfinished_tasks == 0 :
290- self ._finished .set ()
291-
292- @coroutine
293- def join (self ):
294- """Block until all items in the queue have been gotten and processed.
295-
296- The count of unfinished tasks goes up whenever an item is added to the
297- queue. The count goes down whenever a consumer thread calls task_done()
298- to indicate that the item was retrieved and all work on it is complete.
299- When the count of unfinished tasks drops to zero, join() unblocks.
300- """
301- if self ._unfinished_tasks > 0 :
302- yield from self ._finished .wait ()
285+ JoinableQueue = Queue
286+ """Deprecated alias for Queue."""
0 commit comments