В Python-скрипте, использующем multiprocessing.Manager() для обмена словарями между процессами, наблюдается взаимная блокировка — приведите минимальный пример кода, объясните причину дедлока и предложите корректный способ организации обмена данными

10 Мар в 09:01
13 +1
0
Ответы
1
Пример минимального кода, приводящего к дедлоку (две RLock берутся в разном порядке):
```python
from multiprocessing import Process, Manager
from time import sleep
def p1(l1, l2, d1):
with l1: # захват первой блокировки
sleep(0.1) # имитируем работу
with l2: # ждём вторую — может привести к дедлоку
d1['p1'] = 'ok'
def p2(l1, l2, d2):
with l2: # захват во втором процессе в обратном порядке
sleep(0.1)
with l1:
d2['p2'] = 'ok'
if __name__ == '__main__':
mgr = Manager()
d1 = mgr.dict()
d2 = mgr.dict()
l1 = mgr.RLock()
l2 = mgr.RLock()
proc1 = Process(target=p1, args=(l1, l2, d1))
proc2 = Process(target=p2, args=(l1, l2, d2))
proc1.start()
proc2.start()
proc1.join() # программа зависнет здесь из‑за взаимной блокировки
proc2.join()
```
Причина дедлока (кратко):
- Manager создаёт серверные объекты (прокси) для словарей и замков. Каждый `RLock` — отдельный синхронизируемый ресурс в сервере.
- Процесс A берёт `l1` и ждёт `l2`, в то же время процесс B берёт `l2` и ждёт `l1` — классический deadlock из‑за разного порядка захвата ресурсов.
Корректные способы организации обмена данными (рекомендации и пример):
1) Использовать очереди для обмена сообщениями (рекомендуется). Очереди проще и меньше подвержены дедлокам:
```python
from multiprocessing import Process, Queue
def p1(q_send, q_recv):
q_send.put('message from p1')
msg = q_recv.get() # блокируемся, но обмен упорядочен через очереди
print('p1 got', msg)
def p2(q_send, q_recv):
q_send.put('message from p2')
msg = q_recv.get()
print('p2 got', msg)
if __name__ == '__main__':
q1 = Queue() # очередь для сообщений в p1
q2 = Queue() # очередь для сообщений в p2
a = Process(target=p1, args=(q2, q1)) # p1 пишет в q2, читает из q1
b = Process(target=p2, args=(q1, q2))
a.start(); b.start()
a.join(); b.join()
```
2) Если всё же нужны общие структуры:
- Соблюдать единый порядок захвата замков во всех процессах (глобальный порядок ресурсов).
- Или избегать больших критических секций: читать/писать быстро и не держать замок во время долгой работы.
- Использовать неблокирующие попытки с таймаутом и повторной попыткой (backoff) для предотвращения зависания.
3) Альтернативы:
- Возвращать результаты через Pool/Process (через return / Queue), использовать shared memory (`multiprocessing.Value`/`Array`) для простых числовых данных, или специализированные библиотеки (Redis, ZeroMQ) для сложного обмена.
Короткое резюме: дедлок возникает из‑за захвата нескольких менеджерных замков в разном порядке; проще и надежнее обмениваться сообщениями через `multiprocessing.Queue` или обеспечить строгий единый порядок захвата ресурсов.
10 Мар в 09:44
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир