【问题标题】:Tornado ThreadPoolExecutor delays requests when yielding resultsTornado ThreadPoolExecutor 在产生结果时延迟请求
【发布时间】:2019-06-21 16:31:42
【问题描述】:

系统规范 - macOS 10.13.6 - Python 3.7.0 - 龙卷风 5.1.1

我想使用 ThreadPoolExecutor 来运行阻塞函数 在提供 RESTful 服务的 Tornado 实例中。

只要我不尝试产生已执行函数返回的结果,ThreadPool 就会按预期工作并并行生成四个工作线程(请参阅下面的代码和控制台日志)。

ThreadPoolExecutor 不产生结果

import time
import tornado.web
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor
from tornado.ioloop import IOLoop

MAX_WORKERS = 4
i = 0

class Handler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)

    @run_on_executor
    def background_task(self, i):
        print("going sleep %s" % (i))
        time.sleep(10);
        print("waking up from sleep %s" % (i))
        return str(i)

    @tornado.gen.coroutine
    def get(self):
        global i
        i+=1
        self.background_task(i)


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


if __name__ == "__main__":
    app = make_app()
    app.listen(8000, '0.0.0.0')
    IOLoop.current().start()        

控制台输出

going sleep 1
going sleep 2
going sleep 3
going sleep 4
waking up from sleep 1
going sleep 5
waking up from sleep 2
going sleep 6
waking up from sleep 3
going sleep 7
waking up from sleep 4
going sleep 8
waking up from sleep 5
going sleep 9
waking up from sleep 6
waking up from sleep 7
waking up from sleep 8
waking up from sleep 9

可以看出,四个并行工作程序正在运行,一旦一个完成,一个排队的函数就会被执行。

但是,当我尝试使用协程生成返回函数时,我遇到了一些问题。虽然它没有完全阻塞 IoLoop,但它会在没有明确模式的情况下延迟。

更改的代码:ThreadPoolExecutor 现在产生结果

MAX_WORKERS = 4
i = 0

class Handler(tornado.web.RequestHandler):
    executor = ThreadPoolExecutor(max_workers=MAX_WORKERS)

    @run_on_executor
    def background_task(self, i):
        print("%s: Going sleep %s" % (time.time(), i))
        time.sleep(10);
        print("%s: Waiking up from sleep %s" % (time.time(), i))
        return str(i)

    @tornado.gen.coroutine
    def get(self):
        global i
        i+=1
        result = yield self.background_task(i)
        self.write(result)

查看控制台输出,第一个和第二个请求只有一个线程运行,一旦单个线程完成就执行排队任务(导致启动任务 2 延迟 10 秒,启动任务 3 延迟 10 秒)。但是,任务 3、4、5 和 6 是并行执行的,但每次调用之间的延迟不同。

控制台输出

1548687401.331075: Going sleep 1
1548687411.333173: Waking up from sleep 1
1548687411.340162: Going sleep 2
1548687421.3419871: Waking up from sleep 2
1548687421.347039: Going sleep 3
1548687423.4030259: Going sleep 4
1548687423.884313: Going sleep 5
1548687424.6828501: Going sleep 6
1548687431.351986: Waking up from sleep 3
1548687431.3525162: Going sleep 7
1548687433.407232: Waking up from sleep 4
1548687433.407604: Going sleep 8
1548687433.8846452: Waking up from sleep 5
1548687433.885139: Going sleep 9
1548687434.685195: Waking up from sleep 6
1548687434.685662: Going sleep 10
1548687441.3577092: Waking up from sleep 7
1548687441.358009: Going sleep 11
1548687443.412503: Waking up from sleep 8
1548687443.888705: Waking up from sleep 9
1548687444.691127: Waking up from sleep 10
1548687451.359714: Waking up from sleep 11

谁能解释这种行为?你有什么解决办法吗?

【问题讨论】:

  • 您是如何生成请求的?如果您使用浏览器选项卡,您可能会遇到tornadoweb.org/en/stable/…
  • 嗨@BenDarnell,谢谢你的指点。事实上,我尝试使用多个选项卡、Postman 和在我的浏览器中运行的 ionic 实例。所有人都有我一定错过的文档中描述的问题。它按预期工作。如果您回答,我会将您的评论标记为正确。再次感谢。

标签: python tornado threadpoolexecutor


【解决方案1】:

根据 CPU 和工作负载的配置,进程拆分任务。我们可以通过简单的启动 chrome 选项来验证并发性。

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 2013-01-08
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2012-01-03
  • 1970-01-01
相关资源
最近更新 更多