【问题标题】:Share state between threads in bottle在瓶中的线程之间共享状态
【发布时间】:2019-01-25 02:44:21
【问题描述】:

在我在pythonanywhere 上运行的Bottle 应用程序中,我希望在请求之间保留对象。

如果我这样写:

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)。

以下是Bottle docs 对他们的 request 对象的评价:

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

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

【问题讨论】:

  • 如果你有多个instance(实际上是process),它就会停止工作。这是通过进程共享变量。
  • 对于request 对象,我相信这不是您想要的。因为您想在多个请求之间保持不变。

标签: python multithreading thread-safety bottle


【解决方案1】:

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

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

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

你熟悉 Redis 吗?那会在我的候选名单上。

【讨论】:

  • 感谢您花时间回答这个问题。我想我应该更清楚地说明,数据库中的存储状态对于我想要实现的目标来说不是一个可行的解决方案。我之前设置过 Redis,但只是作为 Django 的一部分,它只存储简单的对象而不是复杂的状态,所以不认为它可以与它一起使用。
【解决方案2】:

我通过联系 PythonAnywhere 支持来获得答案,他们有这样的说法:

当您在免费 PythonAnywhere 帐户上运行网站时,只需 一个进程处理你的所有请求——所以一个全局变量像 你在那里使用的那个会很好。但只要你想扩大规模 起来,并获得(比如说)一个黑客帐户,那么您将拥有多个进程 (不是,不是线程)——当然,每个线程都有自己的全局 变量,所以事情会出错。

因此,该部分涉及 PythonAnywhere 的具体工作原理,以及何时停止工作。

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

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

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

Ps:我没想到其他回复会告诉我将状态存储在数据库中,我认为我问这个事实意味着我有充分的理由不使用数据库,为浪费时间道歉!

【讨论】:

    猜你喜欢
    • 2012-05-10
    • 1970-01-01
    • 2010-11-12
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 1970-01-01
    • 2016-01-25
    相关资源
    最近更新 更多