python - 在 Jupyter Notebook 中运行 Tornado 服务器
问题描述
采用标准 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"))
以上在标准 python 脚本中工作得很好(尽管它缺少安全关闭)。Jupyter notebook 是这些交互式 Tornado 服务器环境的最佳环境。然而,当涉及到 Jupyter 时,这个想法就被打破了,因为已经有一个活跃的运行循环:
>>> import asyncio
>>> asyncio.get_event_loop()
<_UnixSelectorEventLoop running=True closed=False debug=False>
在 Jupyter 笔记本中运行上述脚本时会出现这种情况,服务器和请求客户端都试图在同一个线程中打开连接并且代码挂起。构建一个新的 Asyncio 循环和/或 Tornado IOLoop 似乎没有帮助,我怀疑我在 Jupyter 本身中遗漏了一些东西。
问题:是否可以在 Jupyter 笔记本的后台运行实时 Tornado 服务器,以便标准 pythonrequests
或类似的可以从主线程连接到它?如果可能的话,我宁愿在呈现给用户的代码中避免使用 Asyncio,因为它对于新手用户来说相对复杂。
解决方案
根据我最近对 streamz 的 PR,这里有一些可行的方法,类似于你的想法:
class InNotebookServer(object):
def __init__(self, port):
self.port = port
self.loop = get_ioloop()
self.start()
def _start_server(self):
from tornado.web import Application, RequestHandler
from tornado.httpserver import HTTPServer
from tornado import gen
class Handler(RequestHandler):
source = self
@gen.coroutine
def get(self):
self.write('Hello World')
application = Application([
('/', Handler),
])
self.server = HTTPServer(application)
self.server.listen(self.port)
def start(self):
"""Start HTTP server and listen"""
self.loop.add_callback(self._start_server)
_io_loops = []
def get_ioloop():
from tornado.ioloop import IOLoop
import threading
if not _io_loops:
loop = IOLoop()
thread = threading.Thread(target=loop.start)
thread.daemon = True
thread.start()
_io_loops.append(loop)
return _io_loops[0]
在笔记本中调用
In [2]: server = InNotebookServer(9005)
In [3]: import requests
requests.get('http://localhost:9005')
Out[3]: <Response [200]>
推荐阅读
- android - 如何忽略触摸事件,让安卓系统处理?
- android - BottomAppBar 忽略“layout_gravity”,始终显示在顶部
- python - 允许来自我的 zappa 应用程序的“ObjectCreated”事件通知
- javascript - 如何重写此 JavaScript 行以便于阅读?(三元运算符)
- ios - 当尝试从统一构建一个 Xcode 项目到我的 iPhone 时,它给了我这个错误 Apple Mach-O Linker (Id) Error
- oracle - 是否可以创建触发器以将表的数据插入到 Oracle 中的另一个表中?
- php - PHP/HTML 中的语法错误 - 解析错误
- python - Python:多处理输出问题
- c++ - 为什么有时需要将 c++ 模板函数定义放在头文件中?
- mysql - mysql 在另一个流行值查询的结果中找到一个流行值