【问题标题】:Why does the following snippet of multi-processing code output differently when running multiple times?为什么以下多处理代码片段在多次运行时输出不同?
【发布时间】:2020-09-15 23:56:11
【问题描述】:

直观地说,输出应始终为 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}')

【问题讨论】:

  • 在我看来像比赛条件

标签: python multiprocessing pool


【解决方案1】:

增量运算符+= 不是原子的。这意味着以这种方式使用是不安全的。当您调用此运算符时,值会被读取,然后用增加的值替换。如果第二个进程更改了这两个操作之间的值,则更改将丢失。

看到这个答案: Is the += operator thread-safe in Python?

【讨论】:

    【解决方案2】:

    你的问题是这样的说法:

    dic['count'] += c
    

    它读取您的字典,然后按 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}')
    

    这可确保整个字典操作保持原子性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-16
      • 1970-01-01
      • 1970-01-01
      • 2021-01-30
      相关资源
      最近更新 更多