Python:短生命周期键的线程安全字典,这样对吗?

1 投票
1 回答
1109 浏览
提问于 2025-04-16 01:44
import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()
def do_thing(job_id):
    _mainlock.acquire() #Dictionary modification lock acquire
    _job_locks.setdefault(job_id, threading.RLock()) #Possibly modifies the dictionary
    _mainlock.release()
    _job_locks[job_id].acquire()
    try:
        one_time_init(job_id)
    finally:
        _job_locks[job_id].release()
    #On function return, the weakref.WeakValueDictionary should cause the key to evaporate

假设有一个叫做 do_thing() 的函数,它会在很多线程中被多次调用,这些线程的 ID 号码可能相同,也可能不同(比如,有4次是 ID 3,还有一次是其他不同的 ID)。这样做是线程安全的吗?对于某个特定的工作 ID,one_time_init() 会不会在同一时间运行超过一次?(顺便说一下,one_time_init 会保存它已经运行过的状态,所以如果它已经完成过一次调用,再次调用就不会有任何效果)


更新后的代码(感谢 THC4k):

import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()

def do_thing(job_id):
    with _mainlock:
        jl = _job_locks.setdefault(job_id, threading.RLock())
    with jl:
        one_time_init(job_id)

1 个回答

4

看起来非常安全。那为什么还需要_job_locks呢?如果one_time_init已经检查过它是否运行过了,你可以直接在那儿加个锁。为什么用RLock而不是Lock(这个函数似乎不会被重复调用)呢?

总之,with语句看起来要好很多:

import threading
import weakref
_mainlock = threading.RLock()
_job_locks = weakref.WeakValueDictionary()

def do_thing(job_id):
    with _mainlock:
        _job_locks.setdefault(job_id, threading.RLock())
    with _job_locks[job_id]:
        one_time_init(job_id)

撰写回答