我有一个用Flask编写的Web服务, Package 在WSGIContainer
中,由Tornado使用其FallbackHandler
机制提供服务。我在flask Web服务中的一个路由运行了一个非常长的操作(大约需要5分钟才能完成),当此路由被触发时,对任何路由的所有其他调用都将被阻止,直到操作完成。我如何解决此问题?
以下是使用Tornado处理Flask应用程序的方式:
parse_command_line()
frontend_path = os.path.join(os.path.dirname(__file__),"..","webapp")
rest_app = WSGIContainer(app)
tornado_app = Application(
[
(r"/api/(.*)", FallbackHandler, dict(fallback=rest_app)),
(r"/app/(.*)", StaticFileHandler, dict(path=frontend_path))
]
)
5条答案
按热度按时间frebpwbc1#
我创建了一个自定义的
WSGIHandler
,它通过使用ThreadPoolExecutor
支持Tornado中WSGI应用的多线程请求。所有对WSGI应用的调用都在单独的线程中执行,因此即使WSGI响应花费很长时间,主循环也保持空闲。以下代码基于this Gist并进行了扩展,以便:目前,代码只在Python 3.4中测试过,所以我不知道它是否能在Python 2.7中工作。它也还没有进行压力测试,但到目前为止似乎工作得很好。
下面是一个简单的Flask应用程序,它演示了
WSGIHandler
。hello()
函数阻塞一秒钟,因此如果您的ThreadPoolExecutor
使用20个线程,您将能够同时加载20个请求(在一秒钟内)。stream()
函数创建一个迭代器响应,并在5秒内将50个数据块传输到客户端。由于迭代器的每次加载都会产生一个新的executor.submit()
,因此很可能来自流响应的不同块将从不同的线程加载,从而破坏Flask对线程局部变量的使用。mxg2im7a2#
Tornado的WSGI容器的可伸缩性不是很好,只有当你有特殊的理由在同一个进程中合并WSGI和Tornado应用程序时才应该使用。任何可能需要花费较长时间的操作都需要使用Tornado的本地异步接口而不是WSGI。
参见文档中的警告:
WSGI是一个同步接口,而Tornado的并发模型基于单线程异步执行。这意味着使用Tornado的WSGIContainer运行WSGI应用的可伸缩性低于在多线程WSGI服务器(如gunicorn或uwsgi)中运行相同的应用。仅当在同一进程中结合Tornado和WSGI的好处超过可伸缩性降低时,才使用WSGIContainer。
sr4lhrrt3#
您可以考虑使用tornado-threadpool,在这种情况下,您的请求将立即返回,任务将在后台完成。
pgx2nnw84#
你可以使用Ladon的任务型方法来处理这些长时间的操作。
它为这些类型的情况提供了框架解决方案。
Ladon Tasks documentation
pcrecxhr5#
当龙卷风与Flask一起工作时,请查看WSGIContainer模型的源代码,并且...请查看下面的示例代码!!!
运行此示例时,tornado应用程序的侦听速率为5000,我们可以进行一些测试:
1.请求路由'/1'和请求路由'/2'同时发出,并且您应该同时获得响应(均在5秒内)
1.同时请求路由'/1'和请求路由'/3',您应该立即从路由'/3'获得响应,并在5秒内从路由'/1'获得响应
1.同时请求路由'/1'和请求路由'/1'(如在不同的浏览器选项卡中),您应该在5秒内从路由'/1'获得第一个响应,并在10秒内从路由'/1'获得第二个响应