async-kernel¶
async-kernel provides Python Jupyter kernels and clients compatible with CPython (Jupyter & VS code) and Pyodide (Jupyterlite).
The kernel interface supports multiple connections including:
- Messaging via ZMQ sockets (Jupyter, VS Code, etc).
- Same-process local client (Jupyterlite).
Highlights¶
- Built using aiologic thread-safe synchronisation primitives.
- The
Callerclass provides a powerful but simple interface for cross-thread code execution in asyncio and trio backends, with guest event loop support built in. - A zmq poll event loop for thread-safe zmq sockets.
- IPython shell
- top-level await (asyncio or trio backend) in cells
- async magic function support in cells
- Per-subshell user_ns
- GUI event loops 1
- Experimental support for
Jupyterlite (try it online here 👈)
%pip installmagic (using micropip)
- Debugger client
- Local client.
- ZMQ client.
Installation¶
pip install async-kernel
Kernelspecs¶
A kernelspec with the name 'async' is added when async-kernel is installed.
Kernel specs can be installed/uninstalled via the command line.
async-kernel install
# To install for a user
async-kernel install --user
For further detail about kernel spec customisation see command line and kernel configuration and custom kernel.ipynb.
Faster data serialization¶
orjson (a fast JSON library) is supported and will be used by default if it has been installed.
Free-threading support¶
async-kernel's Caller's are thread-local and it's methods are internally synchronised4.
Origin¶
async-kernel started as a fork of IPyKernel. Thank you to the original contributors of IPyKernel that made async-kernel possible.
How it works¶
async-kernel provides concurrent message handling using a per-msg_type handlers and Caller to run the handlers.
When a connection receives a message it wraps the message in a Job and calls
Kernel.handle_request. The kernel gets a handler for the job and decides a Caller
to use. One of three methods on the Caller is used to run the Job in the handler.
queue_call(default): A single task is created for thehandlerwhich maintains a queue and executes jobs first-in-first-out.call_soon: A new task is created for thehandlerandJob.to_thread: A worker caller thread is used to run thehandlerwith theJob.
Execute requests can modify how the handler is run.
flowchart TD
Client
Caller("`Using one of:
- Caller.queue_call
- Caller.call_soon
- Caller.to_thread
`")
Connection
get_handler("`get_handler
(from cache of handlers)`")
handler("Message handler")
Client == Request ==> Connection == Job ==> handle_request
handler -. Content .-> Connection
Connection -. Reply .-> Client
get_caller --Schedules execution ---> Caller -- Task --> handler
subgraph Kernel
handle_request ==> get_handler ==> get_caller
end
-
A gui (host) enabled kernel interface starts a gui's mainloop (host) which starts the backend as a guest, then finally the Kernel is started. ↩
-
The asyncio implementation of
start_guest_runwas written by the author of aiologic and provided as a gist. ↩↩ -
trio's start_guest_run. ↩↩