如何在多进程/多线程 mod_wsgi 中共享变量

48 阅读4分钟

能否在多线程/多进程 WSGI 中共享一个对象(并且可以在 *NIX 和 Windows 上运行)? 基本的假设: (1) 我有一个将连接到后端服务器的 WSGI 前端。我有一个序列化类,其中包含有关如何序列化/反序列化各种对象的规则,包括此项目特有的类。因此,它需要一些设置来告诉它如何处理自定义对象。但是,它在其他方面是无状态的 - 多个线程可以同时访问它来序列化他们的数据而不会出现问题。 (2) 有连接到后端的套接字。我宁愿有一个套接字池,而不是每次有连接时都创建/销毁。 注意:我不介意(1)和(2)存在多个实例的解决方案,但理想情况下,我希望它们尽可能少地创建/初始化。我不确定内部情况,但如果线程循环而不是关闭并让服务器在新的请求上重新打开,那么每个线程有一个数据集是合适的(因此,套接字和序列化器每个线程初始化一次,但是它处理的每个后续调用都会重复使用)。如果这是它的工作方式,实际上每个线程都有一个套接字是最好的,因为我不需要一个套接字池并处理互斥量。 注意:这不是会话,也与会话无关。这应该不在乎谁在向服务器拨打电话。它只是关于调整在具有缓慢线程创建或大量内存但相对较慢的 CPU 的系统上的性能。 编辑 2:下面的代码将提供一些有关您的系统如何共享变量的信息。您需要加载页面几次才能获得一些诊断...

from datetime import *;
from threading import *;
import thread;
from cgi import escape;
from os import getpid;

count = 0;
responses = [];
lock = RLock();

start_ident = "%08X::%08X" % (thread.get_ident(), getpid());

show_env = False;

def application(environ, start_response):
    status = '200 OK';
    this_ident = "%08X::%08X" % (thread.get_ident(), getpid());


    lock.acquire();
    current_response = """<HR>
<B>Request Number</B>: """ + str(count) + """<BR>
<B>Request Time</B>: """ + str(datetime.now()) + """<BR>
<B>Current Thread</B>: """ + this_ident  + """<BR>
<B>Initializing Thread</B>: """ + start_ident  + """<BR>
Multithread/Multiprocess: """ + str(environ["wsgi.multithread"]) + "/" + str(environ["wsgi.multiprocess"]) +"""<BR>
"""
    global count;
    count += 1;

    global responses;
    responses.append(current_response)
    if(len(responses) >= 100):
        responses = responses[1:];
    lock.release();

    output="<HTML><BODY>";

    if(show_env):
        output+="<H2>Environment</H2><TABLE><TR><TD>Key</TD><TD>Value</TD></TR>";
        for k in environ.keys():
            output += "<TR><TD>"+escape(k)+"</TD><TD>"+escape(str(environ[k]))+"</TD></TR>";
        output+="</TABLE>";
    output += "<H2>Response History</H2>";
    for r in responses:
        output += r;
    output+="</BODY></HTML>"


    response_headers = [('Content-type', 'text/html'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output]

2、解决方案 答案 1: 要了解有关 mod_wsgi 进程/线程模型如何工作的一些阅读内容,请参阅:

code.google.com/p/modwsgi/w…

特别注意有关构建可移植应用程序的部分。 无论使用什么 WSGI 服务器,那里的注释实际上没有任何不同。所有 WSGI 服务器也属于多进程/单进程、多线程/单线程类别之一。

答案 2: 根据我对 code.google.com/p/modwsgi/w… 的阅读,如果您启用了多处理和多线程(如使用 worker,或者如果您有

WSGIDaemonProcess example processes=2 threads=25

那么你就有两个问题:多线程意味着你可以共享一个变量,但它只能在 2 个进程中的每一个内部共享。除非您明确地让另一个守护进程(非 APACHE)处理消息传递和请求,否则无法在进程之间真正共享变量。 假设您只需要一个数据库连接池。使用上面的配置,您将拥有两个池,每个池为 25 个线程提供服务。这对大多数人来说是可以的,因为线程是轻量级的,而进程不是(据称)。 那么,如何实现这一点呢?

在您的某个模块中,创建一个实例化连接池的变量。让每个线程(实际上,为单个请求提供服务的代码)在适当的时候获取一个连接使用它,然后将其返回给池。不要忘记最后的部分,您会很快用尽连接。 创建一个另一个守护进程(与 Apache 无关)。实例化一个共享内存数组。在此数组中放置由数据库连接和进程 ID(启动时为 null)组成对象。在一个 while-True 循环中,监听套接字上的连接,当您收到一个连接时,生成一个子进程,传递共享数组、数组元素的编号。子进程填入它知道的进程 ID,它处理请求,关闭任何游标,然后删除其进程 ID 并退出。 聘请一位熟悉 WSGI 和数据库连接池的程序员为您完成这项工作;-)。