哪些Web服务器与gevent兼容,它们之间如何关系?
我想用Flask和它的SocketIO插件开始一个网页项目,而这个插件需要用到gevent(这是个跟绿色线程有关的东西),但是我不太明白gevent和网络服务器有什么关系。使用gevent会限制我选择服务器吗?它和我们在Python中常见的不同类型的网络服务器(比如Nginx/Apache,Gunicorn)有什么关系呢?
谢谢你的解答。
1 个回答
首先,让我们澄清一下我们在讨论什么:
gevent
是一个库,可以让我们更简单地编写事件循环。这意味着它可以让我们快速返回响应,而不会让请求者等待。socket.io
是一个 JavaScript 库,用来创建可以与服务器保持永久连接的客户端,服务器可以发送事件。然后,这个库可以对这些事件做出反应。greenlet
可以理解为一个线程。它是一种启动多个工作者来完成任务的方式。
下面是整个过程的一个非常简单的概述:
想象一下你正在创建一个聊天客户端。
你需要一种方法来通知用户的屏幕,当有人输入消息时。为了实现这一点,你需要一种方式告诉所有用户,有新消息可以显示。这就是 socket.io
的作用。你可以把它想象成一个调到特定频率的收音机。每当有人在这个频率上发送信息时,代码就会做某些事情。在聊天程序中,它会把消息添加到聊天框中。
当然,如果你有一个调到某个频率的收音机(你的客户端),那么你需要一个广播电台/ DJ 来在这个频率上发送信息。这就是你的 Flask 代码的作用。它会创建“房间”,然后发送消息。客户端会监听这些消息。
你也可以用 Node.js 在 socket.io
中编写服务器端(“广播电台”)代码,但这不在我们讨论的范围内。
这里的问题是,传统上 - 一个网页服务器的工作方式是这样的:
- 用户在浏览器中输入一个地址,然后按下回车(或点击前往)。
- 浏览器读取这个网址,然后通过 DNS 系统找到服务器的 IP 地址。
- 它与服务器建立连接,然后发送请求。
- 网页服务器接受请求。
- 它进行一些工作,或者启动某个进程(这取决于请求的类型)。
- 它准备(或接收)来自进程的响应。
- 它将响应发送给客户端。
- 它关闭连接。
在第 3 步到第 8 步之间,客户端(浏览器)在等待响应 - 它被 阻塞,无法做其他事情。所以如果某个地方出现问题,比如某个服务器端脚本处理请求的时间太长,浏览器就会停留在加载图标旋转的白屏上。在整个过程完成之前,它无法做任何事情。这就是网络设计的工作方式。
这种“阻塞”架构对于一对一的通信效果很好。但是,对于多个用户保持更新,这种阻塞就不太适用了。
事件库(gevent
)可以帮助解决这个问题,因为它们接受请求而不会阻塞客户端;它们会立即发送响应,并在处理完成后再返回。
然而,你的应用程序仍然需要通知客户端。但是,由于连接已经关闭,你没有办法再联系客户端。
为了通知客户端,并确保客户端不需要“刷新”,应该保持一个永久连接 - 这就是 socket.io
的作用。它打开一个永久连接,并始终监听消息。
- 所以工作请求从一端发来 - 被接受。
- 工作被执行,响应由其他程序生成(可能是同一个程序或另一个程序)。
- 然后,发送一个通知“嘿,我完成了你的请求 - 这是响应”。
- 第一步中的人监听这个消息,然后采取行动。
在这一切的背后是 WebSocket,这是一种新的全双工协议,使得所有这些广播/DJ 功能成为可能。
WebSocket 和 HTTP 之间的共同点:
- 在同一个端口(80)上工作
- WebSocket 请求最初是作为 HTTP 请求进行握手(一个 升级头),但随后切换到 WebSocket 协议 - 此时连接被交给一个支持 WebSocket 的服务器。
你传统的网页服务器只需监听这个握手请求,确认它,然后将请求传递给一个支持 WebSocket 的服务器 - 就像处理其他正常的代理请求一样。
- 对于 Apache,你可以使用
mod_proxy_wstunnel
- 对于 nginx 1.3 及以上版本,内置了 WebSocket 支持