2

我正在使用带有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")

somedict 会是线程安全的吗?如果运行一个守护线程来管理某个字典,比如说它是一个活动会话的字典并且守护线程修剪过期的会话怎么办?如果不是,一个简单的锁定机制就足够了,我是否需要在读取、写入和在守护线程中使用它,或者只是在守护线程中使用它?

另外据我了解,cherrypy 是一个真正的多线程服务器。在使用cherrypy作为python线程不是真正的线程时,是否应该使用更合适的方法来暗示守护程序线程?我不想深入研究cherrypy环境,更愿意在这个项目中坚持使用bottle,所以如果它涉及从bottle/将我的应用程序迁移到cherrypy,那么现在这并不重要。我仍然想知道,因为我在他们关于线程的文档中没有看到太多。

4

3 回答 3

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")
于 2013-11-09T20:44:28.493 回答
0

CherryPy 基于 Python 线程,因此您应该避免将其仅用作 HTTP 服务器(以及任何其他本机 HTTP 服务器)。我建议您使用 uWSGI,它是多进程的,因此没有 GIL 问题。由于它是多进程的,因此您将无法使用简单的线程共享变量。您可以使用 uWSGI 的 SharedArea 或任何第三方数据存储。

于 2013-11-09T17:21:33.203 回答
0

我最初回答说 adict是线程安全的,但在进一步研究中,这个答案是错误的。请参阅此处以获得很好的解释。

为了快速解释,假设有两个线程同时运行此代码:

d['k'] += 1

它们可能同时读取d['k'],因此不会增加 2,而是仅增加 1。

我认为这不是您的应用程序锁定的问题,更多的是丢失了一些数据。如果这不可接受,那么使用threading.Lock非常容易,并且不会增加太多开销。

这里有一些关于 CherryPy 线程安全的好信息。您也可以考虑使用gunicorn之类的东西来代替 CherryPy。它有一个工作进程模型,因此每个somedict进程的每个进程都是不同的,因此不必担心线程安全。

于 2013-11-08T03:15:44.277 回答