单个Flask进程接收多少并发请求?

210

我正在使用Flask构建一个应用程序,但不太了解WSGI及其基于HTTP的框架Werkzeug。当我使用gunicorn和4个工作进程来启动Flask应用程序时,这是否意味着我可以处理4个并发请求?

我的意思是并发请求,并不是每秒请求数或其他任何内容。

4个回答

266

运行开发服务器时,通过运行app.run()命令,你得到的是一个单个同步进程,这意味着最多只能处理一个请求。

如果将Gunicorn放在默认配置中,并增加--workers的数量,你将获得一些由Gunicorn管理的进程,每个进程都像app.run()开发服务器一样运行。4个工作进程等于4个并发请求。这是因为Gunicorn默认使用包含sync工作器类型的方式。

需要注意的是,Gunicorn还包括异步工作进程,即eventletgevent(还有tornado,但最好与Tornado框架一起使用)。通过使用--worker-class标志来指定其中一个异步工作进程,你将获得Gunicorn管理的一些异步进程,每个进程都管理自己的并发性。这些进程不使用线程,而是使用协程。基本上,在每个进程内,仍然只能同时发生1件事情(1个线程),但当对象正在等待外部进程完成(例如数据库查询或等待网络I/O)时,对象可以被“暂停”。

这意味着,如果你使用Gunicorn的异步工作进程,每个工作进程可以同时处理多个请求。最佳工作进程数量的确定取决于你的应用程序性质、其环境、运行硬件等等。更多详细信息可以在Gunicorn设计页面以及gevent工作方式说明上找到。


11
自 Gunicorn 19 版本开始,现在支持“真正”的线程。请参见此链接此链接 - Filipe Correia
3
如何跟踪哪些资源在线程/进程之间共享(以及如何共享),哪些是完全独立的?例如,如果我想在由Gunicorn处理并在Flask处理程序中使用的多个进程之间共享一个庞大的数据结构,我该怎么处理? - jpp1
那么Eve呢?这对Eve也适用吗? - Eswar
7
自Flask v1.0版本以来,Flask开发服务器默认使用线程。(来源:https://github.com/pallets/flask/pull/2529) - hychou
GIL 会影响 Flask 应用程序的线程吗? - Venkataramana
显示剩余4条评论

77

目前有一种比已提供的解决方案简单得多的方法。当您运行应用程序时,只需将threaded=True参数传递给app.run()调用即可:

app.run(host="your.host", port=4321, threaded=True)

根据我们在Werkzeug文档中所见,另一个选项是使用processes参数,它接收大于1的数字,表示处理并发进程的最大数量:

  • threaded - 进程是否应将每个请求分配给单独的线程?
  • processes - 如果大于1,则在新进程中处理每个请求,直到达到此最大并发进程数。

类似这样:

app.run(host="your.host", port=4321, processes=3) #up to 3 processes

注意: 在Flask文档中,关于run()方法指出在生产环境中使用它是不被推荐的,因为(引用): "虽然轻量且易用,但Flask内置的服务器在生产环境中不适合使用,因为它无法很好地扩展。"

然而,他们指向了他们的部署选项页面,以获取建议的生产环境下的解决方案。

有关run()方法的更多信息,请参见此处,以及带领我找到解决方案和API参考的博客文章


7
感谢提供信息。需要注意的是,关于运行文档中指出了它不应在生产环境中使用,因为它不符合安全性或性能要求。 - luv2learn
1
@Coffee_fan,你说得对。即使在最新的1.1.x版本中,他们也不鼓励这样做,而是建议在进行生产时检查他们的部署选项页面。感谢您宝贵的观察意见 :) - DarkCygnus

44

Flask每次只能处理一个线程的请求。如果你有2个进程,每个进程有4个线程,那就是8个并发请求。

Flask不会生成或管理线程或进程,这是WSGI网关(例如gunicorn)的责任。


12

不,你绝对可以处理更多。

重要的是要记住,在深层次上,假设你正在运行单核机器,CPU 实际上只能同时运行一条指令*。

也就是说,CPU 只能执行非常有限的一组指令,并且它不能在每个时钟周期内执行多个指令(许多指令甚至需要多个周期)。

因此,我们在计算机科学中谈论的大多数并发都是软件并发。换句话说,有许多软件实现层将底层 CPU 抽象出来,使我们认为我们正在同时运行代码。

这些“东西”可以是进程,它们是以单位代码形式并发运行的,每个进程都认为自己在自己的世界中运行,具有自己的非共享内存。

另一个例子是线程,它们是进程内的代码单元,也允许并发。

你的 4 个工作进程之所以能够处理超过 4 个请求,是因为它们会启动线程来处理越来越多的请求。

实际请求限制取决于所选择的 HTTP 服务器、I/O、操作系统、硬件、网络连接等。

祝你好运!

*指令是 CPU 可以运行的基本命令。例如-将两个数字相加,从一个指令跳转到另一个指令


1
是gunicorn生成线程还是Flask?我没有找到支持任何一种可能性的证据。 - jd.
1
这个答案不包含任何关于Flask或gunicorn的信息。 - jwg
7
假设你正在运行一台单核处理器的电脑,实际上CPU只能同时执行一条指令,这种说法是不正确的。现代大多数CPU都采用了流水线和超标量技术,即使是单核处理器也有多个执行单元和指令解码器,将软件端看到的“机器码”转换成实际的硬件微操作,然后分派给各个执行单元。 - Michael Geary
2
澄清一下,早期的 CPU 实际上直接执行可执行文件中的数字指令-机器码。每个 CPU 参考手册都有一个指令时序图,显示每个指令需要多少时钟周期,包括任何内存引用。因此,您可以将所有时序加起来,就知道任何代码需要多长时间才能执行完毕。但现代 CPU 并非如此。一个有趣的例外是BeagleBone,它具有现代超标量 ARM 处理器和两个传统的固定指令定时的“PRU”处理器。 - Michael Geary
2
为了澄清,当我说“现代”时,我是在使用它作为处理器的松散简写,例如ARM / Intel / AMD芯片-流水线,超标量等。当然,还有一些现代处理器以旧方式工作,每个指令具有固定的时间,例如我提到的BeagleBone PRUs和各种新型微控制器。(现在回到Gunicorn!) - Michael Geary
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接