Python中的多进程共享变量

55

第一个问题是Value和Manager().Value之间的区别是什么?

第二个问题是是否可以在不使用Value的情况下共享整数变量? 以下是我的示例代码。我想要得到一个具有整数值的字典,而不是Value。我所做的只是在操作后全部更改它。有没有更简单的方法?

from multiprocessing import Process, Manager

def f(n):
    n.value += 1

if __name__ == '__main__':
    d = {}
    p = []

    for i in range(5):
        d[i] = Manager().Value('i',0)
        p.append(Process(target=f, args=(d[i],)))
        p[i].start()

    for q in p:
        q.join()

    for i in d:
        d[i] = d[i].value

    print d

2
相关:http://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing - Chris_Rands
1个回答

69
当使用Value时,您将获得一个在共享内存中的ctypes对象,默认情况下使用RLock进行同步。当使用Manager时,您将获得一个SynManager对象,该对象控制一个服务器进程,允许其他进程操作对象值。您可以使用同一个管理器创建多个代理;您不需要在循环中创建新的管理器。
manager = Manager()
for i in range(5):
    new_value = manager.Value('i', 0)

Manager可以在多台计算机之间共享,而Value仅限于一台计算机。 Value速度更快(运行下面的代码查看),因此我认为您应该使用它,除非您需要支持任意对象或通过网络访问它们。

import time
from multiprocessing import Process, Manager, Value


def foo(data, name=''):
    print(type(data), data.value, name)
    data.value += 1


if __name__ == "__main__":
    manager = Manager()
    x = manager.Value('i', 0)
    y = Value('i', 0)

    for i in range(5):
        Process(target=foo, args=(x, 'x')).start()
        Process(target=foo, args=(y, 'y')).start()

    print('Before waiting: ')
    print('x = {0}'.format(x.value))
    print('y = {0}'.format(y.value))

    time.sleep(5.0)
    print('After waiting: ')
    print('x = {0}'.format(x.value))
    print('y = {0}'.format(y.value))

总结:

  1. 使用 Manager 创建多个共享对象,包括字典和列表。使用 Manager 在网络上共享数据。
  2. 当不需要跨网络共享信息并且 ctypes 中的类型足够满足您的需求时,请使用 ValueArray
  3. ValueManager 更快。

警告

顺便提一下,如果可能的话应该避免在进程/线程之间共享数据。上面的代码可能会按预期运行,但是增加执行 foo 所需的时间将导致出现奇怪的情况。请将其与以下内容进行比较:

def foo(data, name=''):
    print type(data), data.value, name
    for j in range(1000):
        data.value += 1

为了使这个功能正常工作,您需要一个Lock

我对所有这些不是特别了解,所以也许会有其他人提供更多的见解。我觉得我应该贡献一个答案,因为这个问题没有得到关注。


2
@user2435611,Array 将为您提供一个共享的 ctypes 数组。您需要事先决定存储的数据类型,并提供一个 类型代码。例如,a = Array('c', 10) 创建了一个长度为 10 的单字符字符串数组。可以像这样向数组添加新条目:a[0] = 'b'。您不能向数组添加任何值,请参见类型代码列表 - ChrisP
3
@ChrisP,虽然我来晚了,但你能否建议一下如何在一台机器上的进程之间分享一个简单的整型变量? 我使用多进程处理IO密集型任务(在学习异步编程之前),希望有一个计数器可以让它们共享,以便我知道它们已经完成了多少次迭代。 你有什么最佳实践的建议吗? - Travis Leleu
1
@TravisLeleu,你找到解决方案了吗? - Connor
1
你应该使用“锁(Lock)”来保护“值(Value)”,请参见https://eli.thegreenplace.net/2012/01/04/shared-counter-with-pythons-multiprocessing。 - soulmachine
1
似乎它在Py3上无法运行。 - Jirka
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接