【问题标题】:class attributes and memory shared between Processes in process pool?进程池中进程之间共享的类属性和内存?
【发布时间】:2019-02-01 03:38:00
【问题描述】:

我有一个类A,它在启动时会更改一个可变类属性nums

当使用maxtasksperchild= 1 通过进程池启动类时,我注意到nums 具有几个不同进程的值。这对我来说是一种不受欢迎的行为。

我的问题是:

  • 进程是否共享内存?
  • 我不理解maxtasksperchild 和进程池的工作原理吗?

编辑:我猜池会腌制它启动的先前进程(而不是原始进程),从而保存nums 的值,对吗?如果是这样,我该如何强制它使用原始流程?

这是一个示例代码:

from multiprocessing import Pool


class A:
    nums = []

    def __init__(self, num=None):
        self.__class__.nums.append(num)  # I use 'self.__class__' for the sake of explicitly
        print(self.__class__.nums)
        assert len(self.__class__.nums) < 2  # checking that they don't share memory


if __name__ == '__main__':
    with Pool(maxtasksperchild=1) as pool:
        pool.map(A, range(99))  # the assert is being raised

EDIT 因为 k.wahome 的回答:使用实例属性不能回答我的问题我需要使用类属性,因为在我的原始代码中(此处未显示)我每个进程有多个实例.我的问题是关于多处理池的工作原理。


顺便说一句,执行以下操作确实有效

from multiprocessing import Process

if __name__ == '__main__':
    prs = []
    for i in range(99):
        pr = Process(target=A, args=[i])
        pr.start()
        prs.append(pr)
    [pr.join() for pr in prs]
# the assert was not raised

【问题讨论】:

    标签: python multiprocessing python-multiprocessing process-pool


    【解决方案1】:

    您的观察还有另一个原因。 nums 中的值不是来自其他进程,而是来自 same 进程,当它开始托管多个 A 实例时。发生这种情况是因为您没有在 pool.map 中将 chunksize 设置为 1 -称呼。 在您的情况下设置 maxtasksperchild=1 是不够的,因为一个任务仍然会消耗整个可迭代块。

    此方法将可迭代对象分割成多个块,将它们作为单独的任务提交给进程池。这些块的(近似)大小可以通过将 chunksize 设置为正整数来指定。 docs about map

    【讨论】:

      【解决方案2】:

      共享很可能是通过具有类属性nums 的映射类A 进入的。

      类属性是类绑定的,因此属于类本身,是在加载类时创建的,它们将被所有实例共享。所有对象都对类属性具有相同的内存引用。

      与类属性不同,实例属性是实例绑定的,不被各种实例共享。每个实例都有自己的实例属性副本。

      查看类 vs 实例属性效果:

      1.使用nums 作为类属性 class_num.py

      from multiprocessing import Pool
      
      
      class A:
      nums = []
      
      def __init__(self, num=None):
          # I use 'self.__class__' for the sake of explicitly
          self.__class__.nums.append(num)
          print("nums:", self.__class__.nums)
          # checking that they don't share memory
          assert len(self.__class__.nums) < 2
      
      
      if __name__ == '__main__':
      with Pool(maxtasksperchild=1) as pool:
          print(pool)
          pool.map(A, range(99))  # the assert is being raised
      

      运行这个脚本

      >>> python class_num.py
      nums: [0]
      nums: [0, 1]
      nums: [4]
      nums: [4, 5]
      nums: [8]
      nums: [8, 9]
      nums: [12]
      nums: [12, 13]
      nums: [16]
      nums: [16, 17]
      nums: [20]
      nums: [20, 21]
      nums: [24]
      nums: [24, 25]
      nums: [28]
      nums: [28, 29]
      nums: [32]
      nums: [32, 33]
      nums: [36]
      nums: [36, 37]
      nums: [40]
      nums: [40, 41]
      nums: [44]
      nums: [44, 45]
      nums: [48]
      nums: [48, 49]
      nums: [52]
      nums: [52, 53]
      nums: [56]
      nums: [56, 57]
      nums: [60]
      nums: [60, 61]
      nums: [64]
      nums: [64, 65]
      nums: [68]
      nums: [68, 69]
      nums: [72]
      nums: [72, 73]
      nums: [76]
      nums: [76, 77]
      nums: [80]
      nums: [80, 81]
      nums: [84]
      nums: [84, 85]
      nums: [88]
      nums: [88, 89]
      nums: [92]
      nums: [92, 93]
      nums: [96]
      nums: [96, 97]
      multiprocessing.pool.RemoteTraceback: 
      """
      Traceback (most recent call last):
        File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 119, in worker
          result = (True, func(*args, **kwds))
        File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 44, in mapstar
          return list(map(*args))
        File "class_num.py", line 12, in __init__
          assert len(self.__class__.nums) < 2
      AssertionError
      """
      
      The above exception was the direct cause of the following exception:
      
      Traceback (most recent call last):
        File "class_num.py", line 18, in <module>
          pool.map(A, range(99))  # the assert is being raised
        File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 260, in map
          return self._map_async(func, iterable, mapstar, chunksize).get()
        File "/usr/local/Cellar/python3/3.6.1/Frameworks/Python.framework/Versions/3.6/lib/python3.6/multiprocessing/pool.py", line 608, in get
          raise self._value
      AssertionError
      

      2。使用nums作为实例属性 instance_num.py

      from multiprocessing import Pool
      
      
      class A:
      
          def __init__(self, num=None):
              self.nums = []
              if num is not None:
                  self.nums.append(num)
              print("nums:", self.nums)
              # checking that they don't share memory
              assert len(self.nums) < 2
      
      
      if __name__ == '__main__':
          with Pool(maxtasksperchild=1) as pool:
              pool.map(A, range(99))  # the assert is being raised
      

      运行这个脚本

      >>> python instance_num.py
      nums: [0]
      nums: [1]
      nums: [2]
      nums: [3]
      nums: [4]
      nums: [5]
      nums: [6]
      nums: [7]
      nums: [8]
      nums: [9]
      nums: [10]
      nums: [11]
      nums: [12]
      nums: [13]
      nums: [14]
      nums: [15]
      nums: [16]
      nums: [17]
      nums: [18]
      nums: [19]
      nums: [20]
      nums: [21]
      nums: [22]
      nums: [23]
      nums: [24]
      nums: [25]
      nums: [26]
      nums: [27]
      nums: [28]
      nums: [29]
      nums: [30]
      nums: [31]
      nums: [32]
      nums: [33]
      nums: [34]
      nums: [35]
      nums: [36]
      nums: [37]
      nums: [38]
      nums: [39]
      nums: [40]
      nums: [41]
      nums: [42]
      nums: [43]
      nums: [44]
      nums: [45]
      nums: [46]
      nums: [47]
      nums: [48]
      nums: [49]
      nums: [50]
      nums: [51]
      nums: [52]
      nums: [53]
      nums: [54]
      nums: [55]
      nums: [56]
      nums: [57]
      nums: [58]
      nums: [59]
      nums: [60]
      nums: [61]
      nums: [62]
      nums: [63]
      nums: [64]
      nums: [65]
      nums: [66]
      nums: [67]
      nums: [68]
      nums: [69]
      nums: [70]
      nums: [71]
      nums: [72]
      nums: [73]
      nums: [74]
      nums: [75]
      nums: [76]
      nums: [77]
      nums: [78]
      nums: [79]
      nums: [80]
      nums: [81]
      nums: [82]
      nums: [83]
      nums: [84]
      nums: [85]
      nums: [86]
      nums: [87]
      nums: [88]
      nums: [89]
      nums: [90]
      nums: [91]
      nums: [92]
      nums: [93]
      nums: [94]
      nums: [95]
      nums: [96]
      nums: [97]
      nums: [98]
      

      【讨论】:

      • 我了解类属性和实例属性之间的区别,但这并不能回答我的问题。我需要使用类属性,因为在我的原始代码(此处未显示)中,每个进程都有多个实例。
      • 我的问题是关于多处理池的工作原理。
      • 哦,我明白了。您从Pool() 获得一个工作进程池。 map 允许您通过本质上将函数应用于可迭代中的每个元素并返回结果来实现执行和数据并行性。因此,您向它提供函数和参数,池中生成的每个子进程都将能够成功导入。
      猜你喜欢
      • 2021-01-17
      • 2021-03-26
      • 1970-01-01
      • 2012-07-03
      • 2023-03-31
      • 2017-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多