【问题标题】:How would you make this Python Dictionary thread-safe?你将如何使这个 Python 字典线程安全?
【发布时间】:2011-12-13 10:33:06
【问题描述】:

我有一个在 Python 中运行的 Web 服务器。服务器是私有的,所以我只希望大约 20 个用户连接到它。服务器是多线程的(目前是 8 个核心,所以我猜是 8 个线程)。

当请求进来时,我能够识别用户。在某些查询中,我需要更新 username -> Boolean 形式的简单 dictionary。我怎样才能使这个线程安全?

【问题讨论】:

  • 您是自己实现服务器还是使用 django、pyramid 或 twisted 之类的东西?

标签: python multithreading


【解决方案1】:

您需要创建一个全局锁对象。

lock = threading.Lock()

然后围绕字典的每次访问获取和释放锁。最简单的方法是使用 new(ish) with syntax

with lock:
    dict[key] = value

【讨论】:

  • 我仅限于使用 Python 2.4,我猜那不可用吗?
  • 不,with 不可用,但您可以使用 lock.acquire() 和 lock.release()。
【解决方案2】:

您可能需要也可能不需要使用锁,这取决于Boolean 的更新方式。

如果Boolean的值依赖于它之前的值,那么就不需要锁:写和读Python字典本身就是线程安全的(除了:@987654321 @ - 但这在单线程中也是不允许的)。内存可见性类似于在某些语言中使用 volatile 实现的效果。

本质上不是线程安全的是“读-修改-写”序列,这会导致竞争条件。如果Boolean 的值 确实 依赖于它之前的值,那么你必须使用锁,因为否则线程 A 可以先读取该值,然后线程 B 可以更改它,然后 A会根据过时的值再次更改它。

【讨论】:

    【解决方案3】:

    如果您需要锁(以避免 Joonas 描述的竞争条件),并且被 Python 2.4 卡住,

    import threading
    lock = threading.Lock()
    
    shared_dict = {}
    
    def do_thing(user, value):
        lock.acquire()
        try:
            shared_dict[user] = value
        finally:
            # Always called, even if exception is raised in try block
            lock.release()
    

    【讨论】:

    • 假设我的作者将其修改包装在该锁下。读者会等到它发布,即写作完成吗?或者我是否也需要将读取内容包含在内?
    • @jeromeG 你可能需要一个类似的锁定功能来读取(再次只是为了避免“读取-修改-写入”竞争条件)
    【解决方案4】:

    在更新字典之前使用threading.LOCK.acquire(),并在更新完成后使用threading.LOCK.release()。

    【讨论】:

    • 这很奇怪,我原以为锁定对象是特定于字典的,有点像 Java 中的同步对象/块/方法......我很困惑
    【解决方案5】:

    你不需要为这个操作锁定字典,因为这个操作是原子的,GIL 会帮你处理。除非你有 read-change-write 之类的操作,否则别担心。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-29
      相关资源
      最近更新 更多