3

我有一个 python(嗯,它现在是 php,但我们正在重写)函数,它接受一些参数(A 和 B)并计算一些结果(在图中找到从 A 到 B 的最佳路径,图是只读的),在典型场景一次调用需要 0.1s 到 0.9s 完成。用户可以通过简单的 REST Web 服务 (GET bestpath.php?from=A&to=B) 访问此功能。当前的实现非常愚蠢-它是一个简单的php脚本+apache+mod_php+APC,每个请求都需要加载所有数据(php数组中超过12MB),创建所有结构,计算路径并退出。我想改变它。

我想要一个具有 N 个独立工作人员的设置(每台服务器 X 和 Y 个服务器),每个工作人员都是一个循环运行的 python 应用程序(获取请求 -> 处理 -> 发送回复 -> 获取请求...),每个工作人员都可以处理一次一个请求。我需要一些可以充当前端的东西:从用户那里获取请求,管理请求队列(具有可配置的超时)并一次向我的工作人员提供一个请求。

如何解决这个问题?你能提出一些设置吗?nginx + fcgi 或 wsgi 还是别的什么?代理?如您所见,我是python、反向代理等方面的新手。我只需要一个关于架构(和数据流)的起点

顺便提一句。工作人员正在使用只读数据,因此无需维护它们之间的锁定和通信

4

7 回答 7

2

看起来您需要“工作人员”成为单独的进程(至少其中一些,因此不妨将它们全部设为单独的进程,而不是将线程束划分为多个进程)。Python 2.6 及更高版本的标准库中的多处理模块提供了很好的工具来生成进程池并通过 FIFO“队列”与它们通信;如果由于某种原因你被 Python 2.5 或更早版本卡住了,那么 PyPi 存储库上有多个版本的多处理,你可以下载这些旧版本的 Python 并使用它们。

“前端”可以而且应该很容易与 WSGI(使用 Apache 或 Nginx)一起运行,并且它可以通过 处理与工作进程之间的所有通信multiprocessing,而无需为此使用 HTTP、代理等系统的一部分;只有前端本身就是一个网络应用程序,工作人员只是按照前端的要求接收、处理和响应工作单元。对我来说,这似乎是最健全、最简单的架构。

Python 的第三方包中还有其他可用的分布式处理方法,但多处理相当不错,并且具有成为标准库一部分的优势,因此,在没有其他特殊限制或约束的情况下,我建议您使用多处理.

于 2009-11-04T16:05:36.707 回答
1

The most simple solution in this case is to use the webserver to do all the heavy lifting. Why should you handle threads and/or processes when the webserver will do all that for you?

The standard arrangement in deployments of Python is:

  1. The webserver start a number of processes each running a complete python interpreter and loading all your data into memory.
  2. HTTP request comes in and gets dispatched off to some process
  3. Process does your calculation and returns the result directly to the webserver and user
  4. When you need to change your code or the graph data, you restart the webserver and go back to step 1.

This is the architecture used Django and other popular web frameworks.

于 2009-11-05T19:09:37.747 回答
1

周围有许多带有预分叉模式和 WSGI 接口的 FastCGI 模块,其中最著名的是flup. 我个人对此类任务的偏好是superfcgi使用 nginx。两者都将启动多个进程并将请求发送给它们。12Mb 并不能在每个进程中单独加载它们,但是如果您想在工作人员之间共享数据,则需要线程,而不是进程。请注意,由于 GIL,具有单进程和多线程的 python 中的繁重数学不会有效地使用多个 CPU/内核。可能最好的方法是使用多个进程(与您拥有的内核一样多),每个进程运行多个线程(默认模式superfcgi)。

于 2009-11-05T15:43:09.343 回答
1

在 Python 中使用线程处理这种安排的典型方法是使用标准库模块Queue。可以在此处找到使用队列模块管理工作人员的示例:队列示例

于 2009-11-04T16:04:49.877 回答
0

另一种选择是数据库中的队列表。
工作进程在循环或关闭 cron 中运行,并轮询队列表以查找新作业。

于 2009-11-11T21:23:51.987 回答
0

您可以使用 nginx 负载平衡器代理到 PythonPaste paster(服务于 WSGI,例如 Pylons),无论如何都会将每个请求作为单独的线程启动。

于 2009-11-04T19:39:24.437 回答
0

我认为您可以配置 modwsgi/Apache,这样它将在单独的进程中随时准备好几个“热”的 Python 解释器,并将它们重用于新的访问(如果它们都很忙,则生成一个新的)。在这种情况下,您可以将所有预处理数据加载为模块全局变量,并且它们只会在每个进程中加载​​一次,并在每次新访问时重用。事实上,我不确定这不是 modwsgi/Apache 的默认配置。

这里的主要问题是您最终可能会消耗大量“核心”内存(但这也可能不是问题)。我认为您也可以为单进程/多线程配置 modwsgi——但我认为,在这种情况下,由于 Python 全局解释器锁(臭名昭著的 GIL),您可能只使用一个 CPU。

不要害怕在 modwsgi 邮件列表中提问——他们非常敏感和友好。

于 2009-11-04T18:25:37.253 回答