我正在使用带有cherrypy服务器的瓶子来利用多线程。据我了解,这使得每个请求都由不同的线程处理。所以给出以下代码:
from bottle import request, route
somedict = {}
@route("/read")
def read():
return somedict
@route("/write", method="POST")
def write():
somedict[request.forms.get("key")] = request.forms.get("value")
某些人是否可以线程安全?如果运行一个守护程序线程来管理某些命令,比如它是一个活动会话字典而守护程序线程修剪过期会话怎么办?如果不是,一个简单的锁定机制就足够了,我是否需要在读取,写入和守护程序线程中,或者只是在守护程序线程中使用它?
另外据我所知,cherrypy是一个真正的多线程服务器。是否有一个更合适的方法我应该用来实现一个守护程序线程,同时使用cherrypy作为pythons线程不是真正的线程?我不想深入研究这个项目中更喜欢坚持使用瓶子的樱桃环境,所以如果它涉及从瓶子移开/将我的应用程序迁移到cherrypy那么它现在并不重要。我仍然想知道,因为我在他们的线程文档中没有看到太多。
答案 0 :(得分:1)
在您的特定示例中,是的,您执行的(单个)dict分配是线程安全的。
somedict[request.forms.get("key")] = request.forms.get("value")
但是,更一般地说,问题的正确答案是: 确实需要使用锁定机制。例如,如果您在处理单个请求时对somedict进行多次更新,并且需要以原子方式进行更新,则会出现这种情况。
好消息是:它可能像互斥体一样简单:
from bottle import request, route
import threading
somedict = {}
somedict_lock = threading.Lock()
@route("/read")
def read():
with somedict_lock:
return somedict
@route("/write", method="POST")
def write():
with somedict_lock:
somedict[request.forms.get("key1")] = request.forms.get("value1")
somedict[request.forms.get("key2")] = request.forms.get("value2")
答案 1 :(得分:0)
我原先回答说dict
是线程安全的,但是在进一步的研究中,答案是错误的。有关详细说明,请参阅here。
为了快速解释,想象一下两个线程一次运行这个代码:
d['k'] += 1
他们可能同时阅读d['k']
,因此不会增加2,而是仅增加1。
我认为这不是你的应用程序锁定的问题,更多的是一些数据丢失。如果这是不可接受的,使用threading.Lock
非常简单,并且不会增加太多开销。
Here's一些关于使用CherryPy进行线程安全的好信息。您也可以考虑使用gunicorn之类的东西代替CherryPy。它有一个工作流程模型,因此每个进程的每个somedict
都不同,因此不必担心线程安全。
答案 2 :(得分:0)
CherryPy基于Python线程,因此您应该远离将其用作HTTP服务器(以及任何其他本机HTTP服务器)。我建议你使用uWSGI,这是多进程的,因此没有GIL问题。由于它是多进程,因此您将无法使用简单的线程共享变量。您可以使用uWSGI的SharedArea或任何第三方数据存储。