【问题标题】:Can a Tornado RequestHandler attend requests, while waiting for a Future to finish?Tornado RequestHandler 可以在等待 Future 完成的同时处理请求吗?
【发布时间】:2015-02-28 23:12:28
【问题描述】:

单个 Tornado RequestHandler 类可以处理新请求,同时等待 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/1localhost:8888/2,这将产生预期的输出。

这正常吗?这是预期的行为吗?

对不起,我的英语不好。

【问题讨论】:

    标签: tornado nonblocking coroutine requesthandler concurrent.futures


    【解决方案1】:

    Tornado 会为每个新请求创建一个 new RequestHandler 实例。所以你的代码确实如你所愿。我运行它并打开两个终端窗口,每个窗口都运行wget localhost:8888/1。您的代码打印:

    Setting up executor ...
    Yielding ...
    Setting up executor ...
    Yielding ...
    ##
    ##
    ##
    Finished!
    Finished!
    

    如您所愿。您可能看到的是您的浏览器不愿意同时打开两个到同一个 URL 的连接。事实上,如果我打开两个选项卡并尝试在两者中加载“localhost:8888/1”,我可以重现您使用 chrome 看到的“阻塞”行为。但是,如果我修改您的代码:

    app = Application([
        ('/1$', Handler1),
        ('/2$', Handler1)])
    

    并在 Chrome 的两个选项卡中打开“localhost:8888/1”和“localhost:8888/2”,我看到它同时打开了两个连接。

    在不受浏览器干扰的情况下尝试 wget 测试。

    【讨论】:

    • 非常感谢!我开始认为我疯了。现在一切都说得通了!我不知道浏览器中有此功能。
    【解决方案2】:

    也适用于我:

    $ 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!
    ##
    ##
    ##
    

    【讨论】:

      猜你喜欢
      • 2015-10-27
      • 1970-01-01
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 2016-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多