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

Bor*_*kov 5 python django multithreading wsgi gil

假设我写了一个wsgi application.我上运行此应用程序Apache2Linux多线程mod-wsgi配置,让我的应用程序在每一个进程的多个线程运行:

WSGIDaemonProcess mysite processes=3 threads=2 display-name=mod_wsgi
WSGIProcessGroup mysite
WSGIScriptAlias / /some/path/wsgi.py
Run Code Online (Sandbox Code Playgroud)

应用程序代码是:

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?
Run Code Online (Sandbox Code Playgroud)

模块foo.py:

a = 1
def racer():
    global a
    a = a + 1
    return str(a)
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 同一个进程内的并发线程访问并修改相同的a变量,所以我的例子不是线程安全的?
  2. 如果我的web服务器是Apache,Linux上我的应用程序的每个线程都是用C语言创建的pthreadsAPI和函数,pthread必须执行的是某种python解释器的主要功能?或者Apache是​​否以某种方式保护我免受此错误的影响?
  3. 如果我是像蟒蛇编写的Web服务器上运行这个TornadoHTTPServer?用python编写的Web服务器将线程实现为python级别的threading.Thread对象,并application在每个线程中运行函数.那么,我想这是一场竞争条件?(我也想,在这种情况下,我可以从底层C级抽象pthreads低于threading.Thread执行和只担心蟒蛇功能,因为解释不会让我修改C级共享数据并拧其运作.所以,唯一的办法打破线程安全对我来说是处理全局变量?是吗?)

Sin*_*ion 4

是的,那里有竞争条件,但它与进口无关。中的全局状态foo.a受到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)
Run Code Online (Sandbox Code Playgroud)

您控制的任何全局可变状态都需要它。