Почему следующий фрагмент кода с множественной обработкой выводится по-разному при многократном запуске? - PullRequest
1 голос
/ 28 мая 2020

Интуитивно понятно, что на выходе всегда должно быть 15. Но иногда он генерирует 11 или 12 или что-то еще. Я попытался добавить немного задержки, но не решил проблему.

from multiprocessing import Pool, Manager
import time

def func(dic, c):
    dic['count'] += c
    # time.sleep(0.1)

if __name__=="__main__":
    d = Manager().dict()    # a manager to enable data sharing b
    d['count'] = 0
    args = [(d,1), (d,2), (d,3), (d,4), (d,5)]
    pool = Pool(5)
    pool.starmap(func, args)   
    pool.close()
    pool.join()
    print(f'dic={d}')

Ответы [ 2 ]

0 голосов
/ 28 мая 2020

Ваша проблема заключается в следующем:

dic['count'] += c

Он читает ваш словарь, затем увеличивается на c и сохраняет значение, но это не операция atomi c. Другой процесс мог изменить словарь между операциями чтения и записи, и тогда ваша запись «перезапишет» изменение, которое произошло между операциями.

Вы можете решить эту проблему, передав блокировку и используя ее:

def func(dic, lock, c):
    with lock:
        dic['count'] += c
    # time.sleep(0.1)

if __name__=="__main__":

    d = Manager().dict()    # a manager to enable data sharing b
    l = Manager().Lock()
    d['count'] = 0
    args = [(d, l,1), (d,l,2), (d,l,3), (d,l,4), (d,l,5)]
    pool = Pool(5)
    pool.starmap(func, args)
    pool.close()
    pool.join()
    print(f'dic={d}')

Это гарантирует, что вся операция словаря останется atomi c.

0 голосов
/ 28 мая 2020

Оператор инкремента += не является atomi c. Это означает, что использовать таким образом небезопасно. Когда вы вызываете этот оператор, значение читается , а затем заменяется увеличенным значением. Если второй процесс изменит значение между этими двумя операциями, это изменение будет потеряно.

См. Этот ответ: Является ли оператор + = потокобезопасным в Python?

...