Skip to content

Commit 5166ecb

Browse files
committed
asyncio_slow: Start new upstream API-compatible asyncio implementation.
The trait of this implementation is that it doesn't use priority queue and time scheduling, and instead does its all operations using polling, starting with such basic one as sleep. On the other hand, this tries to implement all (well, much) of upstream asyncio API and warts. asyncio_slow: Rename from asyncio_micro. It may turn out that this won't be "micro" at all. The main trait of this implementation is that it stay 100% API compatible with upstream (in those APIs which are implemented of course). It will also keep inefficient implementation of event loop scheduling, to discourage its use. Here we go.
1 parent 4c4a743 commit 5166ecb

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

asyncio_slow/asyncio_slow.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import time
2+
import logging
3+
4+
5+
log = logging.getLogger("asyncio")
6+
7+
8+
# Workaround for not being able to subclass builtin types
9+
DoneException = AssertionError
10+
11+
class InvalidStateError:
12+
pass
13+
14+
# Object not matching any other object
15+
_sentinel = []
16+
17+
18+
class EventLoop:
19+
20+
def __init__(self):
21+
self.q = []
22+
23+
def call_soon(self, c, *args):
24+
self.q.append(c)
25+
26+
def run_forever(self):
27+
while self.q:
28+
c = self.q.pop(0)
29+
c()
30+
# I mean, forever
31+
while True:
32+
time.sleep(1)
33+
34+
def run_until_complete(self, coro):
35+
def _cb(val):
36+
raise DoneException
37+
38+
t = async(coro)
39+
t.add_done_callback(_cb)
40+
self.call_soon(t)
41+
try:
42+
self.run_forever()
43+
except DoneException:
44+
pass
45+
46+
def close(self):
47+
pass
48+
49+
50+
_def_event_loop = EventLoop()
51+
52+
53+
class Future:
54+
55+
def __init__(self, loop=_def_event_loop):
56+
self.loop = loop
57+
self.res = _sentinel
58+
self.cbs = []
59+
60+
def result(self):
61+
if self.res is _sentinel:
62+
raise InvalidStateError
63+
return self.res
64+
65+
def add_done_callback(self, fn):
66+
if self.res is _sentinel:
67+
self.cbs.append(fn)
68+
else:
69+
self.loop.call_soon(fn, self)
70+
71+
def set_result(self, val):
72+
self.res = val
73+
for f in self.cbs:
74+
f(self)
75+
76+
77+
class Task(Future):
78+
79+
def __init__(self, coro, loop=_def_event_loop):
80+
super().__init__()
81+
self.loop = loop
82+
self.c = coro
83+
# upstream asyncio forces task to be scheduled on instantiation
84+
self.loop.call_soon(self)
85+
86+
def __call__(self):
87+
try:
88+
next(self.c)
89+
self.loop.call_soon(self)
90+
except StopIteration as e:
91+
log.debug("Coro finished: %s", self.c)
92+
self.set_result(None)
93+
94+
95+
def get_event_loop():
96+
return _def_event_loop
97+
98+
99+
# Decorator
100+
def coroutine(f):
101+
return f
102+
103+
104+
def async(coro):
105+
if isinstance(coro, Future):
106+
return coro
107+
return Task(coro)
108+
109+
110+
class Wait(Future):
111+
112+
def __init__(self, n):
113+
Future.__init__(self)
114+
self.n = n
115+
116+
def _done(self):
117+
self.n -= 1
118+
log.debug("Wait: remaining tasks: %d", self.n)
119+
if not self.n:
120+
self.set_result(None)
121+
122+
def __call__(self):
123+
pass
124+
125+
126+
def wait(coro_list, loop=_def_event_loop):
127+
128+
w = Wait(len(coro_list))
129+
130+
for c in coro_list:
131+
t = async(c)
132+
t.add_done_callback(lambda val: w._done())
133+
loop.call_soon(t)
134+
135+
return w
136+
137+
138+
def sleep(secs):
139+
t = time.time()
140+
log.debug("Started sleep at: %s, targetting: %s", t, t + secs)
141+
while time.time() < t + secs:
142+
time.sleep(0.01)
143+
yield
144+
log.debug("Finished sleeping %ss", secs)

0 commit comments

Comments
 (0)