@@ -148,3 +148,35 @@ Then you may need "shared" memory. This might be the default for
148148threading/async, but is required for multiprocessing and subinterpreters. This
149149is not an option if you are running on multiple machines; then you must transfer
150150serialized objects instead. See the examples in the distributed section.
151+
152+ ## Event loop
153+
154+ One common design for a reactive program is an event loop, where the program is
155+ designed around a central loop, and it reacts to input. This is common with
156+ async programming, but is also used by things like older GUI toolkits without
157+ async, as well. Let's try creating our own from scratch using generators:
158+
159+ ``` {literalinclude} conceptsexample/eventloop.py
160+
161+ ```
162+
163+ In this example, we start with tasks, and loop over them. Each task returns an
164+ estimate of how long it will take. If you were to use one task within another
165+ task, you would need ` yield from ` for the inner task. The loop waits for the
166+ shortest task to be ready, then tries again. It's basic, but the idea is there.
167+
168+ We are using the generator system in Python (asyncio was built originally using
169+ it), but we could have implemented it with the async special methods instead; it
170+ would have been more verbose (since those weren't really designed to be hand
171+ implemented simply), but is quite doable.
172+
173+ Let's try the same thing with asyncio:
174+
175+ ``` {literalinclude} conceptsexample/asyncloop.py
176+
177+ ```
178+
179+ We don't sort the output here, but otherwise, it runs about the same, and takes
180+ the same total amount of time. The difference here is we using a pre-existing
181+ awaitable (sleep), so we have to use ` await ` , which is really just ` yield from `
182+ but using the async-named special methods.
0 commit comments