跨多个mod_wsgi进程/线程共享变量

时间:2013-04-17 10:58:15

标签: python global mod-wsgi wsgi shared

您是否可以在多个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 个答案:

答案 0 :(得分:2)

有关mod_wsgi进程/线程模型如何工作的一些阅读,请参阅:

特别注意构建便携式应用程序的部分。

无论您使用什么WSGI服务器,评论都没有任何不同。所有WSGI服务器也属于这些多进程/单进程,多线程/单线程类别之一。

答案 1 :(得分:2)

通过阅读http://code.google.com/p/modwsgi/wiki/ProcessesAndThreading,如果你有多处理和多线程(与工人一样,或者你有

WSGIDaemonProcess示例进程= 2个线程= 25

然后你有两个问题:多个线程意味着你可以共享一个变量,但它只能在中共享两个进程中的每一个。除非您明确地有另一个守护进程(NON-APACHE)处理消息传递和请求,否则没有真正的方法在进程之间共享变量。

假设您对数据库连接池有一个简单的需求。使用上面的配置,您将拥有两个池,每个池服务25个线程。这对大多数人来说都很好,因为线程是轻量级的并且进程不是(据说)。

那么,如何实现呢?

  • 在其中一个模块中,创建一个实例化连接池的变量。让每个线程(实际上,为单个请求提供服务的代码)在适当的时候获得连接使用它,并将其返回到池中。不要忘记最后一部分,你会很快耗尽连接。

  • 创建另一个守护进程(与Apache无关)。实例化一个共享内存数组。在此数组中放入由数据库连接和进程ID组成的对象(启动时为null)。在while-True循环中,侦听套接字上的连接,当你得到一个时,生成一个子进程,传入共享数组,即数组元素的编号。子进程填充它知道的进程id,它处理请求,关闭任何游标,然后删除其进程ID并退出。

  • 聘请熟悉WSGI和数据库连接池的程序员为你做这件事;-)。