66
77from util import (
88 AsyncQueue ,
9- DummyLock
109 )
1110
1211from time import time
@@ -56,15 +55,13 @@ def write(self, item, block=True, timeout=None):
5655 channel
5756 :param timeout: timeout in seconds for blocking calls.
5857 :raise IOError: when writing into closed file
59- :raise EOFError: when writing into a non-blocking full channel
60- :note: may block if the channel has a limited capacity"""
61- if self ._closed :
62- raise IOError ("Cannot write to a closed channel" )
63-
58+ :raise EOFError: when writing into a non-blocking full channel"""
59+ # let the queue handle the 'closed' attribute, we write much more often
60+ # to an open channel than to a closed one, saving a few cycles
6461 try :
6562 self ._queue .put (item , block , timeout )
66- except Full :
67- raise EOFError ( "Capacity of the channel was exeeded " )
63+ except ReadOnly :
64+ raise IOError ( "Cannot write to a closed channel " )
6865 # END exception handling
6966
7067 def size (self ):
@@ -75,21 +72,10 @@ def size(self):
7572 def close (self ):
7673 """Close the channel. Multiple close calls on a closed channel are no
7774 an error"""
78- mutex = self ._queue .mutex
79- mutex .acquire ()
80- # this is atomic already, due to the GIL - no need to get the queue's mutex
81- print "channel.close()"
75+ # yes, close it a little too early, better than having anyone put
76+ # additional items
8277 self ._closed = True
83- # now make sure that the people waiting for an item are released now
84- # As we it could be that some readers are already on their way to initiate
85- # a blocking get, we must make sure that locks never block before that happens
86-
87- # now we are the only one accessing the queue, so change it
88- self ._queue .mutex = DummyLock ()
89- print self ._queue .not_empty ._waiters
90- self ._queue .not_empty .notify_all ()
91- print self ._queue .not_empty ._waiters
92- mutex .release ()
78+ self ._queue .set_writable (False )
9379
9480 @property
9581 def closed (self ):
@@ -124,6 +110,7 @@ def read(self, count=0, block=True, timeout=None):
124110 If count was < 1, a list with all items that could be read will be
125111 returned."""
126112 # if the channel is closed for writing, we never block
113+ # NOTE: is handled by the queue
127114 if self ._wc .closed or timeout == 0 :
128115 block = False
129116
@@ -160,9 +147,7 @@ def read(self, count=0, block=True, timeout=None):
160147 # could be improved by a separate: no-endtime branch, saving the time calls
161148 for i in xrange (count ):
162149 try :
163- print "about to read" , i , count , block , timeout
164150 out .append (queue .get (block , timeout ))
165- print "got one"
166151 except Empty :
167152 pass
168153 # END ignore empty
@@ -176,7 +161,6 @@ def read(self, count=0, block=True, timeout=None):
176161 # Hence we pop it empty without blocking, getting as much
177162 # as we can. This effectively lets us race ( with mutexes )
178163 # of the other threads.
179- print "stopped because it was closed"
180164 try :
181165 while True :
182166 out .append (queue .get (False ))
@@ -186,11 +170,11 @@ def read(self, count=0, block=True, timeout=None):
186170 # END ignore emptyness, we have all
187171
188172 break
189- # END handle cloased
190-
191- if time () >= endtime :
192- break
193- # END stop on timeout
173+ # END handle channel cloased
174+
175+ if time () >= endtime :
176+ break
177+ # END stop operation on timeout
194178 # END for each item
195179 # END handle blocking
196180 return out
0 commit comments