假设我写了一个wsgi application
。我在Apache2
Linux
上使用多线程mod-wsgi
配置运行此应用程序,以便我的应用程序在每个进程的多个线程中运行:
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
中并且在线程中是相同的(共享的)?
从中得出更多理论问题:
a
变量,所以我的示例不是线程安全的?Apache
,那么Linux上我的应用程序的每个线程都是在C级别上使用pthreads
API创建的,而pthread
必须执行的功能是那种python解释器的主要功能?或者Apache是否以某种方式保护我免受此错误的影响?Tornado
的{{1}}这样的python编写的网络服务器上运行该怎么办?用python编写的Web服务器将线程实现为python级HTTPServer
对象,并在每个线程中运行threading.Thread
函数。那么,我想这是一场竞争条件? (我也想,在这种情况下,我可以从application
实现下面的底层C级pthreads
中抽象出来,并且只关心python函数,因为解释器不允许我修改C级共享数据因此,打破线程安全的唯一方法就是处理全局变量?是吗?)答案 0 :(得分: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)
这将是您控件中任何全局可变状态所需的。
答案 1 :(得分:2)
阅读有关各种进程/线程配置的mod_wsgi文档,特别是有关数据共享的内容。
特别说:
如果仍然使用子进程本地模块中的全局数据, 例如,作为缓存,访问和修改全局数据 必须受到本地线程锁定机制的保护。