How do I run Python asyncio code in a Jupyter notebook?

snth picture snth · Nov 27, 2017 · Viewed 16.4k times · Source

I have some asyncio code which runs fine in the Python interpreter (CPython 3.6.2). I would now like to run this inside a Jupyter notebook with an IPython kernel.

I can run it with

import asyncio
asyncio.get_event_loop().run_forever()

and while that seems to work it also seems to block the notebook and doesn't seem to play nice with the notebook.

My understanding is that Jupyter uses Tornado under the hood so I tried to install a Tornado event loop as recommended in the Tornado docs:

from tornado.platform.asyncio import AsyncIOMainLoop
AsyncIOMainLoop().install()

However that gives the following error:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-1-1139449343fc> in <module>()
      1 from tornado.platform.asyncio import AsyncIOMainLoop
----> 2 AsyncIOMainLoop().install()

~\AppData\Local\Continuum\Anaconda3\envs\numismatic\lib\site- packages\tornado\ioloop.py in install(self)
    179         `IOLoop` (e.g.,     :class:`tornado.httpclient.AsyncHTTPClient`).
    180         """
--> 181         assert not IOLoop.initialized()
    182         IOLoop._instance = self
    183 

AssertionError: 

Finally I found the following page: http://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Asynchronous.html

so I added a cell with the following code:

import asyncio
from ipykernel.eventloops import register_integration

@register_integration('asyncio')
def loop_asyncio(kernel):
    '''Start a kernel with asyncio event loop support.'''
    loop = asyncio.get_event_loop()

    def kernel_handler():
        loop.call_soon(kernel.do_one_iteration)
        loop.call_later(kernel._poll_interval, kernel_handler)

    loop.call_soon(kernel_handler)
    try:
        if not loop.is_running():
            loop.run_forever()
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())
        loop.close()

and in the next cell I ran:

%gui asyncio

That worked but I don't really understand why and how it works. Can someone please explain that to me?

Answer

Felipe picture Felipe · Jul 14, 2018

EDIT FEB 21st, 2019: Problem Fixed

This is no longer an issue on the latest version of Jupyter Notebook. Authors of Jupyter Notebook detailed the case here.

Answer below was the original response that was marked correct by the op.


This was posted quite a bit ago, but in case other people are looking for an explanation and solution to the problem of running asynchronous code inside Jupyter Notebook;

Jupyter's Tornado 5.0 update bricked asyncio functionalities after the addition of its own asyncio event loop:

Terminal output of <code>get_event_loop()</code> Jupyter Notebook output of <code>get_event_loop()</code>

Thus, for any asyncio functionality to run on Jupyter Notebook you cannot invoke a run_until_complete(), since the loop you will receive from asyncio.get_event_loop() will be active.

Instead, you must add task to the current loop:

import asyncio
loop = asyncio.get_event_loop()
loop.create_task(some_async_function())

A simple example running on Jupyter Notebook:

enter image description here