11"""A multi-producer, multi-consumer queue."""
22
3+ from time import time as _time , sleep as _sleep
4+
35class Empty (Exception ):
46 "Exception raised by Queue.get(block=0)/get_nowait()."
57 pass
@@ -29,29 +31,54 @@ def qsize(self):
2931 return n
3032
3133 def empty (self ):
32- """Return 1 if the queue is empty, 0 otherwise (not reliable!)."""
34+ """Return True if the queue is empty, False otherwise (not reliable!)."""
3335 self .mutex .acquire ()
3436 n = self ._empty ()
3537 self .mutex .release ()
3638 return n
3739
3840 def full (self ):
39- """Return 1 if the queue is full, 0 otherwise (not reliable!)."""
41+ """Return True if the queue is full, False otherwise (not reliable!)."""
4042 self .mutex .acquire ()
4143 n = self ._full ()
4244 self .mutex .release ()
4345 return n
4446
45- def put (self , item , block = 1 ):
47+ def put (self , item , block = True , timeout = None ):
4648 """Put an item into the queue.
4749
48- If optional arg 'block' is 1 (the default), block if
49- necessary until a free slot is available. Otherwise (block
50- is 0), put an item on the queue if a free slot is immediately
51- available, else raise the Full exception.
50+ If optional args 'block' is true and 'timeout' is None (the default),
51+ block if necessary until a free slot is available. If 'timeout' is
52+ a positive number, it blocks at most 'timeout' seconds and raises
53+ the Full exception if no free slot was available within that time.
54+ Otherwise ('block' is false), put an item on the queue if a free slot
55+ is immediately available, else raise the Full exception ('timeout'
56+ is ignored in that case).
5257 """
5358 if block :
54- self .fsema .acquire ()
59+ if timeout is None :
60+ # blocking, w/o timeout, i.e. forever
61+ self .fsema .acquire ()
62+ elif timeout >= 0 :
63+ # waiting max. 'timeout' seconds.
64+ # this code snipped is from threading.py: _Event.wait():
65+ # Balancing act: We can't afford a pure busy loop, so we
66+ # have to sleep; but if we sleep the whole timeout time,
67+ # we'll be unresponsive. The scheme here sleeps very
68+ # little at first, longer as time goes on, but never longer
69+ # than 20 times per second (or the timeout time remaining).
70+ delay = 0.0005 # 500 us -> initial delay of 1 ms
71+ endtime = _time () + timeout
72+ while True :
73+ if self .fsema .acquire (0 ):
74+ break
75+ remaining = endtime - _time ()
76+ if remaining <= 0 : #time is over and no slot was free
77+ raise Full
78+ delay = min (delay * 2 , remaining , .05 )
79+ _sleep (delay ) #reduce CPU usage by using a sleep
80+ else :
81+ raise ValueError ("'timeout' must be a positive number" )
5582 elif not self .fsema .acquire (0 ):
5683 raise Full
5784 self .mutex .acquire ()
@@ -80,18 +107,43 @@ def put_nowait(self, item):
80107 Only enqueue the item if a free slot is immediately available.
81108 Otherwise raise the Full exception.
82109 """
83- return self .put (item , 0 )
110+ return self .put (item , False )
84111
85- def get (self , block = 1 ):
112+ def get (self , block = True , timeout = None ):
86113 """Remove and return an item from the queue.
87114
88- If optional arg 'block' is 1 (the default), block if
89- necessary until an item is available. Otherwise (block is 0),
90- return an item if one is immediately available, else raise the
91- Empty exception.
115+ If optional args 'block' is true and 'timeout' is None (the default),
116+ block if necessary until an item is available. If 'timeout' is
117+ a positive number, it blocks at most 'timeout' seconds and raises
118+ the Empty exception if no item was available within that time.
119+ Otherwise ('block' is false), return an item if one is immediately
120+ available, else raise the Empty exception ('timeout' is ignored
121+ in that case).
92122 """
93123 if block :
94- self .esema .acquire ()
124+ if timeout is None :
125+ # blocking, w/o timeout, i.e. forever
126+ self .esema .acquire ()
127+ elif timeout >= 0 :
128+ # waiting max. 'timeout' seconds.
129+ # this code snipped is from threading.py: _Event.wait():
130+ # Balancing act: We can't afford a pure busy loop, so we
131+ # have to sleep; but if we sleep the whole timeout time,
132+ # we'll be unresponsive. The scheme here sleeps very
133+ # little at first, longer as time goes on, but never longer
134+ # than 20 times per second (or the timeout time remaining).
135+ delay = 0.0005 # 500 us -> initial delay of 1 ms
136+ endtime = _time () + timeout
137+ while 1 :
138+ if self .esema .acquire (0 ):
139+ break
140+ remaining = endtime - _time ()
141+ if remaining <= 0 : #time is over and no element arrived
142+ raise Empty
143+ delay = min (delay * 2 , remaining , .05 )
144+ _sleep (delay ) #reduce CPU usage by using a sleep
145+ else :
146+ raise ValueError ("'timeout' must be a positive number" )
95147 elif not self .esema .acquire (0 ):
96148 raise Empty
97149 self .mutex .acquire ()
@@ -115,10 +167,10 @@ def get(self, block=1):
115167 def get_nowait (self ):
116168 """Remove and return an item from the queue without blocking.
117169
118- Only get an item if one is immediately available. Otherwise
170+ Only get an item if one is immediately available. Otherwise
119171 raise the Empty exception.
120172 """
121- return self .get (0 )
173+ return self .get (False )
122174
123175 # Override these methods to implement other queue organizations
124176 # (e.g. stack or priority queue).
0 commit comments