在Jupyter Notebook中运行Tornado服务器

Dan*_*iel 8 python tornado python-asyncio jupyter dask

通过进行标准的Tornado演示并将IOLoop推入后台线程,可以在单个脚本中查询服务器。当Tornado服务器是交互式对象时,这很有用(请参阅Dask或类似内容)。

import asyncio
import requests
import tornado.ioloop
import tornado.web

from concurrent.futures import ThreadPoolExecutor

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

pool = ThreadPoolExecutor(max_workers=2)
loop = tornado.ioloop.IOLoop()

app = make_app()
app.listen(8888)
fut = pool.submit(loop.start)

print(requests.get("https://localhost:8888"))
Run Code Online (Sandbox Code Playgroud)

上面的代码在标准python脚本中可以正常工作(尽管缺少安全关机)。Jupyter Notebook是这些交互式Tornado服务器环境的最佳环境。但是,当涉及到Jupyter时,由于已经存在一个活动的运行循环,所以这个想法失败了:

>>> import asyncio
>>> asyncio.get_event_loop()
<_UnixSelectorEventLoop running=True closed=False debug=False>
Run Code Online (Sandbox Code Playgroud)

在Jupyter笔记本中运行上述脚本时,可以看到这一点,服务器和请求客户端都试图在同一线程中打开连接,并且代码挂起。建立一个新的Asyncio循环和/或Tornado IOLoop似乎没有帮助,我怀疑我在Jupyter本身中缺少了一些东西。

问题:Jupyter笔记本中是否可以在后台运行实时Tornado服务器,以便标准python requests或类似服务器可以从主线程连接到它?我希望尽可能避免在呈现给用户的代码中使用Asyncio,因为它对新手用户而言相对复杂。

Mat*_*att 1

第 1 部分:让嵌套龙卷风

\n\n

要找到您需要的信息,您必须遵循以下 crumbtrails,首先查看IPython 7发行说明中描述的内容\n它特别会向您指出有关文档中 async 和 wait 部分的更多信息,对于此讨论,\n建议使用Nest_asyncio

\n\n

症结如下:

\n\n
    \n
  • A) 要么欺骗 python 运行两个嵌套的事件循环。(nest_asyncio 做什么)
  • \n
  • B) 在已经存在的事件循环上安排协程。(我不知道如何用龙卷风做到这一点)
  • \n
\n\n

我很确定您知道这一切,但我相信其他读者会欣赏的。

\n\n

不幸的是,没有办法让它对用户 \xe2\x80\x93 完全透明,除非你像在 jupyterhub 上一样控制部署,并且可以将这些行添加到自动加载的 IPython 启动脚本中。但我认为以下内容足够简单。

\n\n
import nest_asyncio\nnest_asyncio.apply()\n\n\n# rest of your tornado setup and start code.\n
Run Code Online (Sandbox Code Playgroud)\n\n

第 2 部分:问题同步代码块事件循环。

\n\n

上一节仅关注能够运行龙卷风应用程序。但请注意,任何同步代码都会阻塞事件循环;因此,当运行print(requests.get("http://localhost:8000"))服务器时,由于您阻塞了事件循环,因此服务器似乎无法工作,只有当等待事件循环重新启动的代码完成执行时,服务器才会重新启动...(理解这是留给读者的练习)。您需要print(requests.get("http://localhost:8000")) 从另一个内核发出,或者使用 aiohttp。

\n\n

以下是如何以与请求类似的方式使用 aiohttp。

\n\n
import aiohttp\nsession =  aiohttp.ClientSession()\nawait session.get(\'http://localhost:8889\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下,由于 aiohttp 是非阻塞的,所以事情看起来会正常工作。您在这里可以看到一些额外的 IPython 魔法,我们自动检测异步代码并在当前事件循环上运行它。

\n\n

一个很酷的练习可能是request.get在另一个内核中循环运行,然后sleep(5)在运行tornado的内核中运行,然后看到我们停止处理请求......

\n\n

第三部分:免责声明及其他途径:

\n\n

这是非常棘手的,我建议不要在生产中使用,并警告您的用户这不是推荐的做法。

\n\n

这并不能完全解决你的情况,你需要运行不在主线程中的东西,我不确定这是可能的。

\n\n

您还可以尝试玩其他循环跑步游戏,例如triocurio;它们可能允许您做默认情况下使用 asyncio 无法做的事情,例如嵌套,但这里是 Dragonoons。我强烈推荐 trio 以及围绕其创建的多篇博客文章,特别是如果您正在教授异步。

\n\n

享受吧,希望有所帮助,并请报告错误以及确实有效的事情。

\n