我知道 GIL 阻止 python 跨内核运行其线程。如果是这样,为什么在网络服务器中使用python,像youtube,instagram这样的公司如何处理它。
PS:我知道像多处理这样的替代方案可以解决这个问题。但是,如果有人可以将其发布为他们处理的场景,那就太好了。
Python 用于 Web 服务器中的服务器端处理,但(通常)不作为 Web 服务器。
在正常设置上:我们有Apache或其他Web服务器来处理很多进程(服务器端)(python通常使用wsgi)。请注意,通常 apache 直接处理"静态"文件。所以我们有一个 apache 服务器,许多并行的 apache 进程(处理连接和基本 http)和许多每次处理一个连接的 python 进程。
每个这样的过程都是相互独立的(它们只是使用相同的资源),因此您可以轻松编程服务器端部分,而不必担心死锁。这主要是一种权衡:代码的性能,以及轻松快速地生成代码而不会出现大问题。但通常具有python扩展能力的Web服务器非常好(在大型站点上也是如此),并且服务器比程序员便宜。
注意:一个进程中只有一个请求也会提高安全性。
GIL存在于CPython中(用C语言制作的Python解释器,最常用的),其他解释器版本如Jython或IronPython没有这样的问题,因为它们没有GIL。
即使使用CPython,你仍然可以并发,只需用C做你的事情,然后在你的Python代码中"链接它",就像Numpy或类似的一样。
另一件事是,即使你的页面使用Flask或Django,当你在生产服务器中设置它时,你有一个Apache或Nginx等,它有一个真正的电荷平衡器(或负载均衡器,我现在不记得英文名称)可以同时为许多人提供页面。
从 Flask 文档中获取它(链接):
Flask 的内置服务器不适合生产,因为它不能很好地扩展,并且默认情况下一次只处理一个请求。 [...]
如果要将 Flask 应用程序部署到此处未列出的 WSGI 服务器,请查找有关如何将 WSGI 应用程序与它一起使用的服务器文档。请记住,您的 Flask 应用程序对象是实际的 WSGI 应用程序。
虽然有点晚了,但我会尽量给出一个通用和有用的答案。
@Giacomo Catenazzi的回答很好,但其中某些部分实际上是不正确的。
API 请求(或其他形式的 Web 请求)从已在运行的进程提供服务。这个"已经在运行"进程的创建由一些网络服务器(如 gunicorn)处理,它在启动时创建指定数量的进程,这些进程在您的 Web 应用程序中运行代码,不断等待为任何传入请求提供服务。
不用说,这些进程中的每一个都受到 GIL 的限制,一次只能运行一个线程。但是,一个进程在其生命周期中处理多个(通常为多个)请求。在这里,如果我们能理解请求的流程会更好。
我们将以烧瓶为例,但这适用于大多数 Web 框架。当来自Nginx的请求时,它被移交给gunicorn,后者通过wsgi与您的Web应用程序进行交互。当请求到达框架时,将创建一个应用上下文,并将一些变量推送到应用上下文中。然后它遵循大多数人熟悉的正常路线:路由、数据库调用、响应创建等。然后,响应再次通过wsgi返回给枪角兽。在移交响应时,应用上下文将被拆除。因此,它是应用上下文,而不是在每个新请求上创建的进程。
另外,我只谈到了 gunicorn 中的同步工作线程,但它也有一个异步工作线程选项,它可以通过协程并行处理多个请求。但这是一个单独的话题。
所以回答你的问题:
- Nginx(能够一次处理多个请求)
- Gunicorn 在开始时创建一个包含 n 个进程的池,并且还管理该池,因为如果进程退出或卡住,它会杀死/重新创建并将其添加到池中。
- 每个进程一次处理 1 个请求。
阅读更多关于 gunicorn 的设计以及如何使用它来帮助您实现您的要求。这是关于对烧瓶理解的枪角兽的好线索。这是了解烧瓶应用上下文的绝佳资源