多线程Web服务器上的python wsgi:这是竞争条件吗?

假设我写了一个wsgi应用程序.我在Linux上使用多线程mod-wsgi配置在Apache2上运行此应用程序,以便我的应用程序在每个进程的许多线程中运行:

WSGIDaemonProcess mysite processes=3 threads=2 display-name=mod_wsgi
WSGIProcessGroup mysite
WSGIScriptAlias / /some/path/wsgi.py

应用程序代码是:

def application(environ, start_response):
    from foo import racer
    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return [racer()] #call to racer creates a race condition?

模块foo.py:

a = 1
def racer():
    global a
    a = a + 1
    return str(a)

我是否只是用变量a创建竞争条件?我想,a是一个模块级变量,它存在于foo.py中并且在线程中是相同的(共享的)?

从中得出更多的理论问题:

>同一进程内的并发线程访问并修改相同的变量,所以我的例子不是线程安全的?
>如果我的Web服务器是Apache,我的应用程序在Linux上的每个线程都是在C级创建的,使用pthreads API和pthread必须执行的函数是某种python解释器的主要功能吗?或者Apache是​​否以某种方式保护我免受此错误的影响?
>如果我在像Tornado的HTTPServer这样的python编写的Web服务器上运行它会怎么样?用python编写的Web服务器将线程实现为python级别的threading.Thread对象,并在每个线程中运行应用程序功能.那么,我想这是一场竞争条件? (我也想,在这种情况下,我可以从线程下面的底层C级pthreads中抽象出来.线程实现并且只关心python函数,因为解释器不允许我修改C级共享数据并使其功能失效.所以为我打破线程安全的唯一方法是处理全局变量?是吗?)

解决方法:

是的,那里有竞争条件,但与进口无关. foo.a中的全局状态受到1和a = …之间的数据竞争的影响;因为两个线程可以看到a的相同值,因此计算相同的后继者.

导入机器本身通过进程范围锁定来防止多个线程的重复导入(参见imp.lock_held()).虽然理论上这可能导致死锁,但这几乎从未发生过,因为很少有python模块在导入时锁定其他资源.

这也表明随意修改sys.path可能是安全的;因为这通常仅在导入时发生(为了额外的导入),并且因此线程已经拥有导入锁,其他线程不能导致也会修改该状态的导入.

但是,在racer()中修复比赛非常简单:

import threading
a = 1
a_lock = threading.Lock()

def racer():
    global a
    with a_lock:
        my_a = a = a + 1
    return str(my_a)

在您的控制中,任何全局的,可变的状态都需要它.

上一篇:35 - 并发编程-GIL-多进程


下一篇:Python 线程 的 锁