This document summarizes micro-threading libraries like greenlet, Stackless Python, fibers, and continulets. It explains that greenlet allows lightweight context switching between micro-threads called greenlets. Stackless Python extends CPython with tasklets and channels. PyPy implements greenlets and Stackless using continulets, which are one-shot continuations. Continulets and stacklets provide low-level context switching between continuations. The fibers library provides a higher-level API inspired by greenlets but built on top of stacklets.
6. Greenlet API
greenlet(func, parent=None): creates a greenlet to
run ‘func’
greenlet.switch(*args, **kw): switches execution to
the target greenlet, the first time
func(*args, **kw) will be executed
greenlet.throw([typ, [val, [tb]]]): switches execution
to the target greenlet and raises the specified
exception (GreenletExit by default)
8. How does it work?
‘Stack switching’
Non portable asm code
Copy stack slices on the heap
State is saved and restored when switching
CPU registers
Current Python frame, recursion depth and exception
state
9.
10.
11.
12. How does it work? (II)
Organized in a tree structure
Each greenlet has a ‘parent’, except main
Execution order isn’t always obvious
13. Example (II)
import greenlet
main = greenlet.getcurrent()
def foo_async(cb):
# Will call cb(result, error) eventually
pass
def foo_sync():
current = greenlet.getcurrent()
def cb(result, error):
if error is not None:
current.throw(Exception(error))
else:
current.switch(result)
foo_async(cb)
main.switch()
14. Stackless Python
Fork of CPython, first release in 1999
Provides tasklets and channels
Builtin scheduler
Different approaches to switching
15. Stackless Python (II)
Different ways of switching: soft and hard
Soft switching
“Move some pointers around”
Hard switching
Platform dependent assembly code
When soft-switching is not possible
16. Enter PyPy
New shiny and fast implementation of Python
Vast amount of fairy-dust covered unicorns
included
Includes implementations of both greenlet and
Stackless
Implemented on top of “continulet” objects
17. import _continuation
Continulets are one-shot continuations
Switching code is a standalone C library: stacklet
rpython/translator/c/src/stacklet/
18. Continulet API
continulet(func, *args, **kw): create a continulet
object which will call fun(cont, *args, **kw)
continulet.switch(value=None, to=None): start the
continulet or activate the previously suspended
one. If to is specified a ‘double switch’ is
performed
continulet.throw(type, value=None, tb=None,
to=None): similar to switch, but raise the given
exception after the switch is done
19. Stacklet
Tiny library implementing one-shot continuations
for C
Single C file (~400 lines) + per-platform asm
Supports x86, x86_64 and ARM
Nice and simple API
20. Stacklet API
stacklet_newthread(): creates a new thread handle
stacklet_new(thread_handle, run_func, run_arg):
calls run(arg) in a new stacklet, starts immediately
stacklet_switch(target): switches execution to
target stacklet
22. import fibers
Micro-threadling library API inspired by Python
threads and greenlet
Uses stacklet underneath
Works on CPython and PyPy
On PyPy it uses continulets
github.com/saghul/python-fibers
Or pip install fibers
23. fibers API
Fiber(target=None, args=(), kwargs={},
parent=None): creates a new fiber which will run
“target(*args, **kwargs)”
Fiber.switch(value=None): switch execution to the
target fiber, value can only be passed after the
fiber is running
Fiber.throw(typ, [value, [tb]]): switch execution to
the target fiber and raise the specified exception
24. Motivation
Couldn’t build the API I wanted on top of greenlet
Early binding
More exceptions in expected places
No magic exceptions (GreenletExit)
No switching on GC