我无法理解使用cherrypy / bottle的多线程

时间:2013-11-08 02:40:41

标签: python multithreading cherrypy bottle

我正在使用带有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那么它现在并不重要。我仍然想知道,因为我在他们的线程文档中没有看到太多。

3 个答案:

答案 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或任何第三方数据存储。