web-dev-qa-db-fra.com

Comment exécuter Python code asyncio dans un bloc-notes Jupyter?

J'ai du code asyncio qui fonctionne très bien dans l'interpréteur Python (CPython 3.6.2). Je voudrais maintenant l'exécuter dans un bloc-notes Jupyter avec un noyau IPython.

Je peux l'exécuter avec

import asyncio
asyncio.get_event_loop().run_forever()

et bien que cela semble fonctionner, il semble également bloquer le bloc-notes et ne semble pas jouer à Nice avec le bloc-notes.

Ma compréhension est que Jupyter utilise Tornado sous le capot, j'ai donc essayé de installer une boucle d'événement Tornado comme recommandé dans les documents Tornado :

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

Cependant, cela donne l'erreur suivante:

---------------------------------------------------------------------------
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: 

Enfin, j'ai trouvé la page suivante: http://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Asynchronous.html

j'ai donc ajouté une cellule avec le code suivant:

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()

et dans la cellule suivante j'ai couru:

%gui asyncio

Cela a fonctionné mais je ne comprends pas vraiment pourquoi et comment cela fonctionne. Quelqu'un peut-il m'expliquer cela?

21
snth

EDIT 21 FÉVRIER 2019: Problème résolu

Ce n'est plus un problème sur la dernière version de Jupyter Notebook. Les auteurs de Jupyter Notebook ont ​​détaillé le cas ici .

La réponse ci-dessous était la réponse originale qui a été marquée comme correcte par l'op.


Cela a été publié il y a un peu, mais au cas où d'autres personnes chercheraient une explication et une solution au problème de l'exécution de code asynchrone dans Jupyter Notebook;

La mise à jour Tornado 5.0 de Jupyter a briqué les fonctionnalités asyncio après l'ajout de sa propre boucle d'événement asyncio:

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

Ainsi, pour que toute fonctionnalité asyncio s'exécute sur Jupyter Notebook, vous ne pouvez pas invoquer une run_until_complete(), car la boucle que vous recevrez de asyncio.get_event_loop() sera active.

Au lieu de cela, vous devez ajouter une tâche à la boucle actuelle:

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

Un exemple simple fonctionnant sur Jupyter Notebook:

enter image description here

23
Felipe Faria

Ce n'est plus un problème dans la dernière version de jupyter!

https://blog.jupyter.org/ipython-7-0-async-repl-a35ce050f7f7

Il suffit d'écrire une fonction asynchrone, puis de l'attendre directement dans une cellule jupyter.

async def fn():
  print('hello')
  await asyncio.sleep(1)
  print('world')

await fn()
15
James D

Mon moment aha avec Asyncio dans Jupyter ressemble à ceci:

import time,asyncio

async def count():
    print("count one")
    await asyncio.sleep(1)
    print("count four")

async def count_further():
    print("count two")
    await asyncio.sleep(1)
    print("count five")

async def count_even_further():
    print("count three")
    await asyncio.sleep(1)
    print("count six")

async def main():
    await asyncio.gather(count(), count_further(), count_even_further())

s = time.perf_counter()
await main()
elapsed = time.perf_counter() - s
print(f"Script executed in {elapsed:0.2f} seconds.")

Production:

count one
count two
count three
count four
count five
count six
Script executed in 1.00 seconds.

À l'origine d'ici, mais l'exemple n'était pas clair pour moi au début: https://realpython.com/async-io-python/

J'ai récemment rencontré le problème de ne pas pouvoir exécuter du code asyncio dans un ordinateur portable Jupyter. Le problème est abordé ici: https://github.com/jupyter/notebook/issues/3397

J'ai essayé l'une des solutions dans la discussion et cela a résolu le problème jusqu'à présent.

pip3 install tornado==4.5.3

Cela a remplacé la version 5.x de tornado installée par défaut.

Le code asyncio dans un bloc-notes Jupyter s'est ensuite exécuté comme prévu.

2
DMfll