繁体   English   中英

Python,WSGI,多处理和共享数据

[英]Python, WSGI, multiprocessing and shared data

我对mod_wsgi的多重管理功能以及将在具有多处理能力的WSGI服务器上执行的WSGI应用程序的一般设计感到困惑。

请考虑以下指令:

WSGIDaemonProcess example processes=5 threads=1

如果我理解正确,mod_wsgi将产生5个Python(例如CPython)进程,并且任何这些进程都可以接收来自用户的请求。

文件说:

共享数据需要对所有应用程序实例可见,无论它们执行哪个子进程,并且一个应用程序对数据所做的更改立即可供另一个应用程序使用,包括在另一个子进程中执行的任何子进程,外部数据存储,如必须使用数据库或共享内存。 普通Python模块中的全局变量不能用于此目的。

但是在这种情况下,当想要确定应用程序在任何WSGI条件(包括多处理条件)中运行时,它会变得非常沉重。

例如,一个包含当前连接用户数量的简单变量 - 它应该是从/向memcached进行过程安全读/写,还是DB或(如果有这样的标准库机制可用)共享记忆?

并且代码会像

counter = 0

@app.route('/login')
def login():
    ...
    counter += 1
    ...

@app.route('/logout')
def logout():
    ...
    counter -= 1
    ...

@app.route('/show_users_count')
def show_users_count():
    return counter

在多处理环境中表现不可预测?

谢谢!

您的问题需要考虑几个方面。

首先,apache MPM和mod_wsgi应用程序之间的交互。 如果以嵌入模式运行mod_wsgi应用程序(不需要WSGIDaemonProcessWSGIProcessGroup %{GLOBAL} ),则从apache MPM继承多处理/多线程。 这应该是最快的选项,并且每个进程最终会有多个进程和多个线程,具体取决于您的MPM配置。 相反,如果您在守护进程模式下运行mod_wsgi,使用WSGIDaemonProcess <name> [options]WSGIProcessGroup <name> ,您可以以较小的开销为代价对多处理/多线程进行精细控制。

在单个apache2服务器中,您可以定义零个,一个或多个命名的WSGIDaemonProcess es,并且每个应用程序可以在这些进程之一( WSGIProcessGroup <name> )中运行,或者使用WSGIProcessGroup %{GLOBAL}以嵌入模式运行。

您可以通过检查wsgi.multithreadwsgi.multiprocess变量来检查多处理/多线程。

使用您的配置WSGIDaemonProcess example processes=5 threads=1您有5个独立进程,每个进程都有一个执行线程:没有全局数据,没有共享内存,因为您无法控制产生子进程,但mod_wsgi正在为您执行此操作。 要共享一个全局状态,您已经列出了一些可能的选项:您的进程所连接的数据库,某种基于文件系统的持久性,守护程序进程(在apache之外启动)和基于套接字的IPC。

正如Roland Smith所指出的,后者可以通过multiprocessing.managers使用高级API实现。管理器:你创建并启动BaseManager服务器进程的外部apache

m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.get_server().serve_forever()

在你connect应用程序中:

m = multiprocessing.managers.BaseManager(address=('', 12345), authkey='secret')
m.connect()

上面的例子是虚拟的,因为m没有注册有用的方法,但是在这里 (python docs)你会发现如何在你的进程中创建和代理一个对象(比如你的例子中的counter )。

对您的示例的最终评论, processes=5 threads=1 我知道这只是一个例子,但在现实世界的应用程序中,我怀疑性能与processes=1 threads=5相当processes=1 threads=5 :只有当预期的性能提升超过时,你应该进入多处理共享数据的复杂性。 '单一流程多线程'模型具有重要意义。

从关于wsgi的进程和线程的文档:

当Apache以一种模式运行时,有多个子进程,每个子进程将包含每个WSGI应用程序的子解释器。

这意味着在您的配置中,每个有1个线程的5个进程,将有5个解释器并且没有共享数据。 您的计数器对象对每个解释器都是唯一的。 您需要构建一些自定义解决方案来计算会话(一个可以与之通信的常见流程,某种基于持久性的解决方案等)或者,这绝对是我的建议,使用预构建的解决方案(Google Analytics和Chartbeat是很棒的选择)。

我倾向于使用全局变量来分享数据作为全球滥用的一种重要形式。 在我完成并行处理的大多数环境中,这是一个漏洞和可移植性问题。如果您的应用程序突然在多个虚拟机上运行,​​该怎么办? 无论线程和进程的共享模型是什么,这都会破坏您的代码。

如果使用multiprocessing ,则有多种方法可在进程之间共享数据。 数组仅在进程具有父/子关系(它们由继承共享)时才有效。 如果不是这种情况,请使用ManagerProxy对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM