The Main Loop
2019
Promises and "await"
- Admirał Jachaś
class Promise:
def __init__(self):
self.callback = None
def then(self, callback):
self.callback = callback
def fulfill(self, result):
if self.callback is not None:
self.callback(result)
class FileProcessor:
def __init__(self, input):
self.input = input
def read(self, size):
p = Promise()
# magic
return p
def process(self, data):
p = Promise()
# more magic!
return p
def start(self):
self.read(1024).then(process)
class ReadPromise(Promise):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
handler = ReadHandler(self, self.descriptor, self.size)
main_loop.add(handler)
class ReadHandler:
def __init__(self, promise, descriptor, size):
self.promise = promise
self.descriptor = descriptor
self.size = size
self.data = b''
def should_read(self):
return True
def handle_read(self):
data = self.descriptor.read(self.size)
self.data += data
self.size -= len(data)
if self.size == 0:
self.promise.fulfill(self.data)
class FileProcessor:
def __init__(self, input, output):
self.input = inpit
self.output = output
def read(self, size):
return ReadPromise(self.input, size)
def process(self, data):
return IdlePromise(lambda: frobnicate(data))
def write(self, data):
return WritePromise(self.output, data)
def run(self):
self.read(1024).then(
lambda data: self.process(data).then(
write
)
)
class ComplexProcessor:
def run(self):
self.read(1024).then(
lambda data: self.frobnicate(data).then(
lambda result: self.twiddle(result).then(
lambda result: self.fudge(result).then(
# ...
)
)
)
class Promise:
def __init__(self):
self.callback = None
self.next = Promise()
def then(self, callback):
self.callback = callback
return self.next
def fulfill(self, result):
if self.callback is not None:
result = self.callback(result)
if isinstance(result, Promise):
result.then(self.next.fulfill)
class FileProcessor:
# ...
def run(self):
self.read(1024).then(process).then(write)
class ComplexProcessor:
def run(self):
self.read(1024) \
.then(self.frobnicate) \
.then(self.twiddle) \
.then(self.fudge) \
.then(...)
read
main loop
process
write
a promise chain
def complex_processor():
yield 1
yield 2
yield 3
# ...
>>> g = complex_processor()
>>> g
<generator object complex_processor at 0x7f8900ee7db0>
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
def complex_processor():
yield read()
yield frobnicate()
yield twiddle()
yield fudge()
>>> processor = complex_processor()
>>> next(processor)
<ReadPromise object at 0x7f13992e9128>
>>> next(processor)
<FrobnicatePromise object at 0x7f13992e90f0>
>>> next(processor)
<TwiddlePromise object at 0x7f13992e9128>
>>> next(processor)
<FudgePromise object at 0x7f13992e90f0>
def complex_processor():
result = yield read(1024)
frobnicated = yield frobnicate(result)
twiddled = yield twiddle(frobnicated)
fudged = yield fudge(twiddled)
# ...
g = complex_processor()
reader = send(g, None) # next(g)
frobnicator = send(g, b'some data')
twiddler = send(g, 'some frobnicated data')
fudger = send(g, 'some frobnicated data, but also twiddled')
# ...
def complex_processor():
result = yield read(1024)
frobnicated = yield frobnicate(result)
twiddled = yield twiddle(frobnicated)
fudged = yield fudge(twiddled)
# ...
def step(g, result=None):
send(g, result).then(lambda result: step(g, result))
g = complex_processor()
step(g)
main_loop.run()
read
main loop
process
write
a promise chain
COROUTINE
def read(size):
return file.read(size)
def complex_processor():
result = read(1024)
# ...
def one_two():
yield 1
yield 2
def one_two_three_four():
yield one_two()
yield 3
yield 4
>>> g = one_two_three_four()
>>> next(g)
<generator object one_two at 0x7f13992dfc50>
>>> next(g)
3
>>> next(g)
4
def one_two():
yield 1
yield 2
def one_two_three_four():
yield from one_two()
yield 3
yield 4
>>> g = one_two_three_four()
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
4
def read(size):
result = yield file.read(size)
return result
def frobnicate(data):
result = b''
for i in data:
result += yield frobnicate_byte(i)
return result
def complex_processor():
result = yield from read(1024)
frobnicated = \
yield from frobnicate(result)
# ...
struct generator {
void *next;
};
#define YIELD(g, v) do { \
g->next = &&next##__LINE__; return v; next##__LINE__:; \
} while(0)
int generator(struct generator *g)
{
if (g->next)
goto *g->next;
YIELD(g, 1);
YIELD(g, 2);
}
struct generator g = { .next = NULL };
int one = generator(g);
int two = generator(g);
Thank you
Questions?