在瓶子中的线程之间共享状态

时间:2018-12-20 01:15:23

标签: python multithreading thread-safety bottle

在运行于Bottlepythonanywhere应用中,我希望对象在请求之间得以保留。

如果我写这样的东西:

X = {'count': 0}

@route('/count')
def count():
    X['count'] += 1
    tpl = SimpleTemplate('Hello {{count}}!')
    return tpl.render(count=X['count'])

计数增加,这意味着X在请求之间保持不变。

我目前正在pythonanywhere上运行它,这是一项托管服务,在这里我无法控制Web服务器(我假设是nginx?)线程,负载平衡(如果有)等...

我的问题是,这是巧合吗,因为它仅使用一个线程,而我的测试负载却很小?

更一般而言,这将在什么时候停止?例如。我有多个线程/套接字/实例/负载均衡服务器等?

除此之外,即使必须移动到准系统服务器,做这样的工作(坚持到瓶子)也是我最好的选择。

这是Bottle docs关于其请求对象的内容:

  

LocalRequest的线程安全实例。如果从请求回调中进行访问,则此实例将始终引用当前请求(即使在多线程服务器上)。

但是我不完全了解这意味着什么,或者像我所使用的那样,全局变量在多线程方面的地位。

2 个答案:

答案 0 :(得分:1)

TL; DR:您可能希望使用外部数据库来存储状态。

如果您的应用程序很小,并且您计划始终只运行一个服务器进程,那么您当前的方法可以工作;您需要做的“所有”操作是锁定对共享状态的每次访问(!)(示例代码中的字典X)。 (我把“全部”放在吓人的引号中,因为它可能变得比起初听起来更复杂。)

但是,由于您询问的是多线程,因此我认为您的应用程序不只是玩具,这意味着您计划接收大量流量和/或希望同时处理多个请求。在这种情况下,您将需要多个进程,这意味着您的方法(将状态存储在内存中)无法工作。内存不跨进程共享。跨进程共享状态的(一般)方式是在外部存储状态,例如在数据库中。

您熟悉Redis吗?那将在我的候选人短名单上。

答案 1 :(得分:1)

我可以通过与PythonAnywhere支持人员联系来获得答案,后者的说法是:

  

当您使用免费 PythonAnywhere帐户运行网站时,   一个进程处理您的所有请求-所以像   您在那里使用的那一个很好。但是只要您想扩展   并获得(例如)一个黑客帐户,那么您将有多个流程   (不是线程)-当然每个人都有自己的全局变量   变量,所以事情会出错。

因此,该部分讨论了PythonAnywhere的工作原理以及何时停止在其中工作。

第二部分的答案,关于如何在多个Bottle进程之间共享变量,一旦他们了解数据库在这种情况下将无法正常运行,我也得到了他们的支持(最有帮助!)。

不同的进程当然不能共享变量,最可行的解决方案是:

  

编写自己的缓存服务器以处理将内容保存在内存中的过程。您将有一个始终运行的进程,并且Web API请求将以某种方式对其进行访问(内部REST API?)。它可以将内容保留在内存中[...]

Ps:我没想到会有其他答复告诉我将状态存储在数据库中,我发现我要问的事实意味着我有充分的理由不使用数据库,这很浪费时间!” / p>