如何在Python工作进程中处理长时间运行的请求?
我有一个用Python写的函数(现在是用PHP,但我们正在重写),这个函数需要一些参数(A和B),然后计算出一些结果(在一个图中找到从A到B的最佳路径,这个图是只读的)。在一般情况下,调用这个函数需要0.1秒到0.9秒的时间来完成。用户通过一个简单的REST网络服务来访问这个函数(比如通过GET请求 bestpath.php?from=A&to=B)。目前的实现方式比较简单,就是一个普通的PHP脚本加上Apache服务器和APC缓存,每次请求都需要加载所有的数据(超过12MB的PHP数组),创建所有的结构,计算路径,然后退出。我想要改变这种情况。
我想要一个有N个独立工作者的设置(每台服务器X个工作者,总共Y台服务器),每个工作者都是一个在循环中运行的Python应用程序(获取请求 -> 处理 -> 发送回复 -> 再获取请求...),每个工作者一次只能处理一个请求。我需要一些东西作为前端:接收用户请求,管理请求队列(可以设置超时时间),并且一次给我的工作者提供一个请求。
我该怎么做呢?你能建议一些设置吗?比如nginx加上fcgi或wsgi,或者其他的?haproxy呢?如你所见,我在Python、反向代理等方面还是个新手,我只需要一个关于架构(和数据流)的起点。
顺便说一下,工作者使用的是只读数据,所以不需要在它们之间维护锁定和通信。
7 个回答
在这种情况下,最简单的解决办法就是让网络服务器来处理所有复杂的工作。既然网络服务器可以为你完成这些,为什么还要自己去管理线程或进程呢?
在使用Python的部署中,通常的安排是这样的:
- 网络服务器启动多个进程,每个进程都运行一个完整的Python解释器,并把你的数据加载到内存中。
- 当有HTTP请求进来时,这个请求会被分配给某个进程。
- 这个进程会进行计算,然后直接把结果返回给网络服务器和用户。
- 如果你需要更改代码或图表数据,只需重启网络服务器,然后回到第一步。
这种架构是Django和其他流行的网络框架所使用的。
看起来你需要将“工作者”设置为独立的进程(至少有一些是这样,所以不如把它们都做成独立进程,而不是把多个线程分散到几个进程里)。Python 2.6及以后的标准库中有一个叫做multiprocessing的模块,它提供了很好的功能,可以创建一组进程,并通过FIFO“队列”与它们进行通信;如果你因为某种原因只能使用Python 2.5或更早的版本,PyPi库里也有适用于这些旧版本的multiprocessing的版本可以下载使用。
“前端”可以很容易地用WSGI运行(可以用Apache或Nginx),它可以通过multiprocessing
处理与工作进程之间的所有通信,而不需要使用HTTP、代理等方式;前端本身就是一个网页应用,工作者只需接收、处理并根据前端的请求返回工作结果。这在我看来是最合理、最简单的架构。
还有其他第三方包提供的分布式处理方法,但multiprocessing相当不错,而且它是标准库的一部分,所以如果没有其他特殊的限制或约束,我建议你选择multiprocessing。