1818from graph import Graph
1919from channel import (
2020 mkchannel ,
21- WChannel ,
22- SerialWChannel ,
23- CallbackRChannel
21+ Writer ,
22+ Channel ,
23+ SerialChannel ,
24+ CallbackReader
2425 )
2526
2627import sys
2728import weakref
2829from time import sleep
30+ import new
2931
3032
31- class RPoolChannel (CallbackRChannel ):
32- """ A read-only pool channel may not be wrapped or derived from, but it provides slots to call
33- before and after an item is to be read.
34-
33+ class PoolReader (CallbackReader ):
34+ """A reader designed to read from channels which take part in pools
3535 It acts like a handle to the underlying task in the pool."""
36- __slots__ = ('_task_ref' , '_pool_ref' )
36+ __slots__ = ('_task_ref' , '_pool_ref' , '_read' )
3737
38- def __init__ (self , wchannel , task , pool ):
39- CallbackRChannel .__init__ (self , wchannel )
38+ def __init__ (self , channel , task , pool ):
39+ CallbackReader .__init__ (self , channel )
4040 self ._task_ref = weakref .ref (task )
4141 self ._pool_ref = weakref .ref (pool )
42+ self ._read = new .instancemethod (CallbackReader .__dict__ ['read' ], self , CallbackReader )
4243
4344 def __del__ (self ):
4445 """Assures that our task will be deleted if we were the last reader"""
@@ -63,15 +64,9 @@ def __del__(self):
6364 # okay for now
6465 # TODO: Fix this - private/public method
6566 if sys .getrefcount (self ) < 6 :
66- pool .remove_task (task , _from_destructor_ = True )
67+ pool .remove_task (task )
6768 # END handle refcount based removal of task
6869
69- #{ Internal
70- def _read (self , count = 0 , block = True , timeout = None ):
71- """Direct read, bypassing the pool handling"""
72- return CallbackRChannel .read (self , count , block , timeout )
73- #} END internal
74-
7570 #{ Interface
7671
7772 def pool_ref (self ):
@@ -118,7 +113,7 @@ def read(self, count=0, block=True, timeout=None):
118113 ####### read data ########
119114 ##########################
120115 # read actual items, tasks were setup to put their output into our channel ( as well )
121- items = CallbackRChannel .read (self , count , block , timeout )
116+ items = CallbackReader .read (self , count , block , timeout )
122117 ##########################
123118
124119
@@ -262,21 +257,21 @@ def _prepare_channel_read(self, task, count):
262257 # should make things execute faster. Putting the if statements
263258 # into the loop would be less code, but ... slower
264259 # DEBUG
265- # print actual_count, numchunks, chunksize, remainder, task._out_wc .size()
260+ # print actual_count, numchunks, chunksize, remainder, task._out_writer .size()
266261 if self ._num_workers :
267262 # respect the chunk size, and split the task up if we want
268263 # to process too much. This can be defined per task
269- queue = self ._queue
264+ qput = self ._queue
270265 if numchunks > 1 :
271266 for i in xrange (numchunks ):
272- queue . put ((task .process , chunksize ))
267+ qput ((task .process , chunksize ))
273268 # END for each chunk to put
274269 else :
275- queue . put ((task .process , chunksize ))
270+ qput ((task .process , chunksize ))
276271 # END try efficient looping
277272
278273 if remainder :
279- queue . put ((task .process , remainder ))
274+ qput ((task .process , remainder ))
280275 # END handle chunksize
281276 else :
282277 # no workers, so we have to do the work ourselves
@@ -295,16 +290,16 @@ def _prepare_channel_read(self, task, count):
295290 # END for each task to process
296291
297292
298- def _remove_task_if_orphaned (self , task , from_destructor ):
293+ def _remove_task_if_orphaned (self , task ):
299294 """Check the task, and delete it if it is orphaned"""
300- # 1 as its stored on the task, 1 for the getrefcount call
295+ # 1 for writer on task, 1 for the getrefcount call + 1 for each other writer/reader
301296 # If we are getting here from the destructor of an RPool channel,
302297 # its totally valid to virtually decrement the refcount by 1 as
303298 # we can expect it to drop once the destructor completes, which is when
304299 # we finish all recursive calls
305- max_ref_count = 3 + from_destructor
306- if sys .getrefcount (task .wchannel () ) < max_ref_count :
307- self .remove_task (task , from_destructor )
300+ max_ref_count = 3
301+ if sys .getrefcount (task .writer (). channel ) < max_ref_count :
302+ self .remove_task (task )
308303 #} END internal
309304
310305 #{ Interface
@@ -375,7 +370,7 @@ def num_tasks(self):
375370 finally :
376371 self ._taskgraph_lock .release ()
377372
378- def remove_task (self , task , _from_destructor_ = False ):
373+ def remove_task (self , task ):
379374 """Delete the task
380375 Additionally we will remove orphaned tasks, which can be identified if their
381376 output channel is only held by themselves, so no one will ever consume
@@ -410,7 +405,7 @@ def remove_task(self, task, _from_destructor_=False):
410405 # END locked deletion
411406
412407 for t in in_tasks :
413- self ._remove_task_if_orphaned (t , _from_destructor_ )
408+ self ._remove_task_if_orphaned (t )
414409 # END handle orphans recursively
415410
416411 return self
@@ -421,7 +416,7 @@ def add_task(self, task):
421416 the task will be considered orphaned and will be deleted on the next
422417 occasion."""
423418 # create a write channel for it
424- wctype = WChannel
419+ ctype = Channel
425420
426421 # adjust the task with our pool ref, if it has the slot and is empty
427422 # For now, we don't allow tasks to be used in multiple pools, except
@@ -442,26 +437,29 @@ def add_task(self, task):
442437
443438 # Use a non-threadsafe queue
444439 # This brings about 15% more performance, but sacrifices thread-safety
445- # when reading from multiple threads.
446440 if self .size () == 0 :
447- wctype = SerialWChannel
441+ ctype = SerialChannel
448442 # END improve locks
449443
450444 # setup the tasks channel - respect the task creators choice though
451445 # if it is set.
452- wc = task .wchannel ()
446+ wc = task .writer ()
447+ ch = None
453448 if wc is None :
454- wc = wctype ()
449+ ch = ctype ()
450+ wc = Writer (ch )
451+ task .set_writer (wc )
452+ else :
453+ ch = wc .channel
455454 # END create write channel ifunset
456- rc = RPoolChannel (wc , task , self )
457- task .set_wchannel (wc )
455+ rc = PoolReader (ch , task , self )
458456 finally :
459457 self ._taskgraph_lock .release ()
460458 # END sync task addition
461459
462460 # If the input channel is one of our read channels, we add the relation
463- if hasattr (task , 'rchannel ' ):
464- ic = task .rchannel ()
461+ if hasattr (task , 'reader ' ):
462+ ic = task .reader ()
465463 if hasattr (ic , 'pool_ref' ) and ic .pool_ref ()() is self :
466464 self ._taskgraph_lock .acquire ()
467465 try :
0 commit comments