- 你有一个 Python 函数,它接受一些参数 (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 个独立工作进程的设置,每个工作进程是一个在循环中运行的 Python 应用程序 (获取请求 -> 处理 -> 发送回复 -> 获取请求 ...),每个工作进程一次只能处理一个请求。
- 你需要一些作为前端的东西:从用户那里获取请求,管理请求队列 (具有可配置的超时时间),并一次给工作进程提供一个请求。
2、解决方案
方法一:使用队列模块
- 使用 Python 标准库模块 Queue 来管理工作进程是处理这种安排的典型方法。
- 你可以在这里找到使用 Queue 模块管理工作进程的示例:Queue Example
方法二:使用多进程模块
- 你需要 "工作进程" 是单独的进程 (至少其中一些是,因此不如将它们全部制成单独的进程,而不是分成几个进程的线程组)。
- Python 2.6 及更高版本的标准库中的 multiprocessing 模块提供了良好的工具来生成进程池并通过 FIFO "队列" 与它们通信;如果你由于某种原因被困在 Python 2.5 或更早的版本中,则 PyPi 存储库上有多个版本的 multiprocessing,你可以下载并与那些旧版本的 Python 一起使用。
- "前端" 应该可以很容易地使用 WSGI 运行 (使用 Apache 或 Nginx),它可以通过 multiprocessing 处理与工作进程之间的所有通信,而无需为此部分系统使用 HTTP、代理等;只有前端本身才是 Web 应用程序,工作进程只接收、处理和响应前端请求的工作单元。
- Python 中还有其他分布式处理方法可用于第三方包,但 multiprocessing 非常好,并且具有作为标准库一部分的优势,因此,如果没有其他特殊限制或约束,multiprocessing 是我建议你使用的。
方法三:使用 FastCGI 模块
- 目前有许多具有预先派生模式和 Python 的 WSGI 接口的 FastCGI 模块,其中最著名的是 flup。
- 我个人在执行此类任务时更喜欢使用带 nginx 的 superfcgi。
- 这两者都会启动多个进程,并将请求分派给它们。
- 12Mb 并不足以将它们分别加载到每个进程中,但如果你想在工作进程之间共享数据,你需要线程,而不是进程。
- 请注意,由于 GIL,使用单个进程和许多线程在 python 中进行繁重的数学计算不会有效地使用多个 CPU/核心。
- 最好的方法可能是使用多个进程 (与你的核心数量一样多),每个进程运行多个线程 (superfcgi 中的默认模式)。
方法四:使用 Web 服务器
-
在这种情况下最简单的解决方案是使用 Web 服务器来完成所有繁重的工作。
-
当 Web 服务器将为你完成所有这些工作时,为什么要处理线程和/或进程?
-
Python 部署的标准安排是:
- Web 服务器启动一定数量的进程,每个进程运行一个完整的 Python 解释器,并将所有数据加载到内存中。
- HTTP 请求进入并被分派到某个进程。
- 进程执行你的计算,并将结果直接返回给 Web 服务器和用户。
- 当你需要更改你的代码或图表数据时,你重新启动 Web 服务器并返回到步骤 1。
-
这是 Django 和其他流行的 Web 框架使用的架构。