如何在Python工作进程中处理长时间运行的请求?

4 投票
7 回答
3050 浏览
提问于 2025-04-15 15:39

我有一个用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 个回答

1

在这种情况下,最简单的解决办法就是让网络服务器来处理所有复杂的工作。既然网络服务器可以为你完成这些,为什么还要自己去管理线程或进程呢?

在使用Python的部署中,通常的安排是这样的:

  1. 网络服务器启动多个进程,每个进程都运行一个完整的Python解释器,并把你的数据加载到内存中。
  2. 当有HTTP请求进来时,这个请求会被分配给某个进程。
  3. 这个进程会进行计算,然后直接把结果返回给网络服务器和用户。
  4. 如果你需要更改代码或图表数据,只需重启网络服务器,然后回到第一步。

这种架构是Django和其他流行的网络框架所使用的。

2

在Python中,处理这种线程安排的常见方法是使用标准库中的Queue模块。你可以在这里找到一个使用Queue模块来管理工作线程的例子:Queue示例

2

看起来你需要将“工作者”设置为独立的进程(至少有一些是这样,所以不如把它们都做成独立进程,而不是把多个线程分散到几个进程里)。Python 2.6及以后的标准库中有一个叫做multiprocessing的模块,它提供了很好的功能,可以创建一组进程,并通过FIFO“队列”与它们进行通信;如果你因为某种原因只能使用Python 2.5或更早的版本,PyPi库里也有适用于这些旧版本的multiprocessing的版本可以下载使用。

“前端”可以很容易地用WSGI运行(可以用Apache或Nginx),它可以通过multiprocessing处理与工作进程之间的所有通信,而不需要使用HTTP、代理等方式;前端本身就是一个网页应用,工作者只需接收、处理并根据前端的请求返回工作结果。这在我看来是最合理、最简单的架构。

还有其他第三方包提供的分布式处理方法,但multiprocessing相当不错,而且它是标准库的一部分,所以如果没有其他特殊的限制或约束,我建议你选择multiprocessing。

撰写回答