11# coding: utf8
2+ '''Pool of asyncio coroutines with familiar interface'''
23
34import traceback
5+ import collections
46import asyncio as aio
57
68
79class AioPool (object ):
810
9- def __init__ (self , size = 1024 , loop = None ):
10- self ._size = size
11+ def __init__ (self , size = 1024 , * , loop = None ):
12+ self .loop = loop or aio .get_event_loop ()
13+
14+ self .size = size
1115 self ._waiting = 0
1216 self ._executed = 0
13- self .semaphore = aio .Semaphore (value = self ._size )
14- self .loop = loop or aio .get_event_loop ()
15- self ._all_done = self .loop .create_future ()
17+ self ._joined = collections .deque ()
18+ self .semaphore = aio .Semaphore (value = self .size , loop = self .loop )
19+
20+ async def __aenter__ (self ):
21+ return self
22+
23+ async def __aexit__ (self , ext_type , exc , tb ):
24+ await self .join ()
25+
26+ @property
27+ def n_active (self ):
28+ return self .size - self .semaphore ._value
1629
1730 @property
1831 def is_empty (self ):
19- return 0 == self ._waiting == ( self ._size - self . semaphore . _value )
32+ return 0 == self ._waiting == self .n_active
2033
2134 @property
2235 def is_full (self ):
23- return self ._waiting + ( self ._size - self .semaphore . _value ) >= self . _size
36+ return self .size <= self ._waiting + self .n_active
2437
2538 async def join (self ):
26- await self ._all_done
39+ if self .is_empty :
40+ return True
2741
28- async def __aenter__ (self ):
29- return self
42+ fut = self .loop .create_future ()
43+ self ._joined .append (fut )
44+ try :
45+ return await fut
46+ finally :
47+ self ._joined .remove (fut )
3048
31- async def __aexit__ (self , ext_type , exc , tb ):
32- await self .join ()
49+ def _release_joined (self ):
50+ if not self .is_empty :
51+ raise RuntimeError () # TODO
52+
53+ for fut in self ._joined :
54+ if not fut .done ():
55+ fut .set_result (True )
3356
3457 async def _acquire (self ):
35- if self ._all_done .done ():
36- self ._all_done = self .loop .create_future ()
3758 self ._waiting += 1
3859 await self .semaphore .acquire ()
3960 self ._waiting -= 1
4061
4162 async def _wrap (self , coro , future , cb = None , ctx = None ):
4263 res , exc , tb = None , None , None
64+
4365 try :
4466 res = await coro
4567 future .set_result (res )
@@ -50,10 +72,14 @@ async def _wrap(self, coro, future, cb=None, ctx=None):
5072 self .semaphore .release ()
5173 self ._executed += 1
5274
53- if cb :
54- await self .spawn (cb (res , (exc , tb ), ctx ))
55- elif self .is_empty :
56- self ._all_done .set_result ('done' )
75+ try :
76+ if cb :
77+ await self .spawn (cb (res , (exc , tb ), ctx ))
78+ except Exception as exc_cb :
79+ pass # TODO
80+ finally :
81+ if self .is_empty :
82+ self ._release_joined ()
5783
5884 async def spawn (self , coro , cb = None , ctx = None ):
5985 await self ._acquire ()
0 commit comments