Python: Потокобезопасный словарь с недолговечными ключами, это правильно? - PullRequest
1 голос
/ 23 июля 2010
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 () вызывается много раз во многих потоках с номерами идентификаторов, которые могут совпадать или не совпадать (скажем, 4 раза с идентификатором 3 и один раз с разными идентификаторами), безопасен ли этот поток?Будет ли one_time_init () запускаться более одного раза для определенного идентификатора задания за раз?(PS: 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 голосов
/ 23 июля 2010

Кажется очень безопасно. Зачем вам даже _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)
...