Tornado RequestHandler 可以在等待 Future 完成时处理请求吗?
Can a Tornado RequestHandler attend requests, while waiting for a Future to finish?
单个 Tornado RequestHandler
class 可以处理新请求,同时等待 Future
在其中一个实例中完成吗?
我正在调试一个调用 ThreadPoolExecutor
的 Tornado 协程,我注意到,当协程等待执行程序完成时,RequestHandler
被阻塞了。因此,对这个处理程序的任何新请求都在等待协程完成。
这是我为重现我的观察而编写的代码:
from time import sleep
from concurrent.futures import ThreadPoolExecutor
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado.web import Application, RequestHandler
from tornado.gen import coroutine
class Handler1(RequestHandler):
@coroutine
def get(self):
print('Setting up executor ...')
thread_pool = ThreadPoolExecutor(1)
print('Yielding ...')
yield thread_pool.submit(sleep, 30)
self.write('Ready!')
print('Finished!')
app = Application([('/1$', Handler1)])
app.listen(8888)
PeriodicCallback(lambda: print('##'), 10000).start()
IOLoop.instance().start()
现在,如果我访问 localhost:8888/1
两次,我会得到以下输出:
##
Setting up executor ...
Yielding ...
##
##
##
Finished!
Setting up executor ...
Yielding ...
##
##
##
Finished!
##
但我预计会发生以下情况:
##
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
##
请注意,只有 RequestHandler
似乎被阻止了,因为我们仍然每 10 秒获取一次 ##
。事实上,如果您添加另一个相同的 RequestHandler
(Handler2) 并访问 localhost:8888/1
和 localhost:8888/2
,这将产生预期的输出。
这正常吗?这是预期的行为吗?
抱歉我的英语不好。
Tornado 为每个新请求创建一个 new RequestHandler 实例。所以你的代码确实如你所愿。我 运行 它并打开两个终端 windows,每个 运行ning wget localhost:8888/1
。您的代码打印:
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
如你所料。您可能看到的是您的浏览器不愿意同时打开到同一个 URL 的两个连接。实际上,如果我打开两个选项卡并尝试在两个选项卡中加载 "localhost:8888/1",我可以重现您在 chrome 中看到的 "blocking" 行为。但是,如果我修改你的代码:
app = Application([
('/1$', Handler1),
('/2$', Handler1)])
然后在 Chrome 的两个选项卡中打开 "localhost:8888/1" 和 "localhost:8888/2",我看到它同时打开了两个连接。
在不受浏览器干扰的情况下尝试使用 wget 进行测试。
也适用于我:
$ curl http://127.0.0.1:8888/1 &
[1] 95055
$ curl http://127.0.0.1:8888/1 &
[2] 95056
$ curl http://127.0.0.1:8888/1 &
[3] 95057
Tornado 程序输出:
bash-3.2$ python3 test.py
##
##
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
Finished!
##
##
##
单个 Tornado RequestHandler
class 可以处理新请求,同时等待 Future
在其中一个实例中完成吗?
我正在调试一个调用 ThreadPoolExecutor
的 Tornado 协程,我注意到,当协程等待执行程序完成时,RequestHandler
被阻塞了。因此,对这个处理程序的任何新请求都在等待协程完成。
这是我为重现我的观察而编写的代码:
from time import sleep
from concurrent.futures import ThreadPoolExecutor
from tornado.ioloop import IOLoop, PeriodicCallback
from tornado.web import Application, RequestHandler
from tornado.gen import coroutine
class Handler1(RequestHandler):
@coroutine
def get(self):
print('Setting up executor ...')
thread_pool = ThreadPoolExecutor(1)
print('Yielding ...')
yield thread_pool.submit(sleep, 30)
self.write('Ready!')
print('Finished!')
app = Application([('/1$', Handler1)])
app.listen(8888)
PeriodicCallback(lambda: print('##'), 10000).start()
IOLoop.instance().start()
现在,如果我访问 localhost:8888/1
两次,我会得到以下输出:
##
Setting up executor ...
Yielding ...
##
##
##
Finished!
Setting up executor ...
Yielding ...
##
##
##
Finished!
##
但我预计会发生以下情况:
##
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
##
请注意,只有 RequestHandler
似乎被阻止了,因为我们仍然每 10 秒获取一次 ##
。事实上,如果您添加另一个相同的 RequestHandler
(Handler2) 并访问 localhost:8888/1
和 localhost:8888/2
,这将产生预期的输出。
这正常吗?这是预期的行为吗?
抱歉我的英语不好。
Tornado 为每个新请求创建一个 new RequestHandler 实例。所以你的代码确实如你所愿。我 运行 它并打开两个终端 windows,每个 运行ning wget localhost:8888/1
。您的代码打印:
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
如你所料。您可能看到的是您的浏览器不愿意同时打开到同一个 URL 的两个连接。实际上,如果我打开两个选项卡并尝试在两个选项卡中加载 "localhost:8888/1",我可以重现您在 chrome 中看到的 "blocking" 行为。但是,如果我修改你的代码:
app = Application([
('/1$', Handler1),
('/2$', Handler1)])
然后在 Chrome 的两个选项卡中打开 "localhost:8888/1" 和 "localhost:8888/2",我看到它同时打开了两个连接。
在不受浏览器干扰的情况下尝试使用 wget 进行测试。
也适用于我:
$ curl http://127.0.0.1:8888/1 &
[1] 95055
$ curl http://127.0.0.1:8888/1 &
[2] 95056
$ curl http://127.0.0.1:8888/1 &
[3] 95057
Tornado 程序输出:
bash-3.2$ python3 test.py
##
##
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
Setting up executor ...
Yielding ...
##
##
##
Finished!
Finished!
Finished!
##
##
##