Python 多进程与 class 实例
Python multiprocess with class instance
我有一个问题与我遇到的问题无关,而是与为什么它不是问题有关。也许有点笨,但我对 classes 不是很熟悉,我正在努力学习。
假设我有一个 class 定义如下:
import numpy as np
import multiprocessing as mp
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
self.a = np.random.randint(10)
return self.a + b, self.a
我创建了一个对象:
foo = Foo(1)
然后我想计算不同 b 值的 Sum 的结果,在不同进程之间并行计算:
def Calc(b):
return foo.Sum(b)
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3]
out = pool.map(Calc, b)
print(out)
打印(在一种情况下是随机的):
[(8, 8), (5, 4), (3, 1), (7, 4)]
这是正确的。
我的问题是不同的进程如何同时修改一个 class 属性,在我们的例子中是一个(在这个例子中操作非常快,但在我的真实世界的例子中操作需要几秒钟甚至几分钟,因此并行化)而不影响彼此?
每个进程都使用自己的内存,因此它们不能修改另一个进程的 class 属性。另一方面,如果你对线程做同样的事情——你会遇到竞争条件的问题。
每个进程都是独立的,它们之间没有通信。当您将 foo 对象发送到不同的进程时,它们不再是同一件事——它们中的许多人都在做自己的事情。你的问题不是关于 classes 或 class 实例,而是关于不同进程中发生的事情。
打印实例的 ID 及其 a
属性可以说明。
import multiprocessing as mp
import numpy as np
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
s = f'I am {id(self)}, a before={self.a}'
self.a = np.random.randint(10)
print(f'{s} | a after={self.a}')
return self.a + b, self.a
foo = Foo(1)
def Calc(b):
return foo.Sum(b)
if __name__ == '__main__':
print(f'original foo id:{id(foo)}')
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3, 5, 6, 7, 8]
out = pool.map(Calc, b)
print(out)
print(f'{id(foo)}.a is still {foo.a}')
# not sure why this is necessary
pool.terminate()
然后 运行 从命令提示符:
PS C:\pyprojects> py -m tmp
original foo id:2235026702928
I am 1850261105632, a before=1 | a after=4
I am 1905926138848, a before=1 | a after=1
I am 1850261105632, a before=4 | a after=8
I am 1905926138848, a before=1 | a after=9
I am 1850261105632, a before=8 | a after=2
I am 1905926138848, a before=9 | a after=9
I am 1850261105632, a before=2 | a after=7
I am 1905926138848, a before=9 | a after=3
[(4, 4), (2, 1), (10, 8), (12, 9), (7, 2), (15, 9), (14, 7), (11, 3)]
2235026702928.a is still 1
玩打印字符串:
import multiprocessing as mp
import numpy as np
import os
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
s = f'I am {id(self)}, a: before={self.a}'
self.a = np.random.randint(10)
s = f'{s} | after={self.a}'
return os.getpid(),s,(self.a + b, self.a),b
foo = Foo(1)
def Calc(b):
return foo.Sum(b)
if __name__ == '__main__':
print(f'original foo id:{id(foo)}')
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3, 5, 6, 7, 8]
out = pool.map(Calc, b)
out.sort(key=lambda x: (x[0],x[-1]))
for result in out:
print(f'pid:{result[0]} b:{result[-1]} {result[1]} {result[2]}')
print(f'{id(foo)}.a is still {foo.a}')
pool.terminate()
...
PS C:\pyprojects> py -m tmp
original foo id:2466513417648
pid:10460 b:1 I am 2729330535728, a: before=1 | after=2 (3, 2)
pid:10460 b:3 I am 2729330535728, a: before=2 | after=5 (8, 5)
pid:10460 b:6 I am 2729330535728, a: before=5 | after=2 (8, 2)
pid:10460 b:8 I am 2729330535728, a: before=2 | after=2 (10, 2)
pid:13100 b:0 I am 2799588470064, a: before=1 | after=1 (1, 1)
pid:13100 b:2 I am 2799588470064, a: before=1 | after=6 (8, 6)
pid:13100 b:5 I am 2799588470064, a: before=6 | after=8 (13, 8)
pid:13100 b:7 I am 2799588470064, a: before=8 | after=0 (7, 0)
2466513417648.a is still 1
PS C:\pyprojects>
我有一个问题与我遇到的问题无关,而是与为什么它不是问题有关。也许有点笨,但我对 classes 不是很熟悉,我正在努力学习。 假设我有一个 class 定义如下:
import numpy as np
import multiprocessing as mp
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
self.a = np.random.randint(10)
return self.a + b, self.a
我创建了一个对象:
foo = Foo(1)
然后我想计算不同 b 值的 Sum 的结果,在不同进程之间并行计算:
def Calc(b):
return foo.Sum(b)
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3]
out = pool.map(Calc, b)
print(out)
打印(在一种情况下是随机的):
[(8, 8), (5, 4), (3, 1), (7, 4)]
这是正确的。 我的问题是不同的进程如何同时修改一个 class 属性,在我们的例子中是一个(在这个例子中操作非常快,但在我的真实世界的例子中操作需要几秒钟甚至几分钟,因此并行化)而不影响彼此?
每个进程都使用自己的内存,因此它们不能修改另一个进程的 class 属性。另一方面,如果你对线程做同样的事情——你会遇到竞争条件的问题。
每个进程都是独立的,它们之间没有通信。当您将 foo 对象发送到不同的进程时,它们不再是同一件事——它们中的许多人都在做自己的事情。你的问题不是关于 classes 或 class 实例,而是关于不同进程中发生的事情。
打印实例的 ID 及其 a
属性可以说明。
import multiprocessing as mp
import numpy as np
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
s = f'I am {id(self)}, a before={self.a}'
self.a = np.random.randint(10)
print(f'{s} | a after={self.a}')
return self.a + b, self.a
foo = Foo(1)
def Calc(b):
return foo.Sum(b)
if __name__ == '__main__':
print(f'original foo id:{id(foo)}')
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3, 5, 6, 7, 8]
out = pool.map(Calc, b)
print(out)
print(f'{id(foo)}.a is still {foo.a}')
# not sure why this is necessary
pool.terminate()
然后 运行 从命令提示符:
PS C:\pyprojects> py -m tmp
original foo id:2235026702928
I am 1850261105632, a before=1 | a after=4
I am 1905926138848, a before=1 | a after=1
I am 1850261105632, a before=4 | a after=8
I am 1905926138848, a before=1 | a after=9
I am 1850261105632, a before=8 | a after=2
I am 1905926138848, a before=9 | a after=9
I am 1850261105632, a before=2 | a after=7
I am 1905926138848, a before=9 | a after=3
[(4, 4), (2, 1), (10, 8), (12, 9), (7, 2), (15, 9), (14, 7), (11, 3)]
2235026702928.a is still 1
玩打印字符串:
import multiprocessing as mp
import numpy as np
import os
class Foo(object):
def __init__(self, a):
self.a = a
def Sum(self, b):
s = f'I am {id(self)}, a: before={self.a}'
self.a = np.random.randint(10)
s = f'{s} | after={self.a}'
return os.getpid(),s,(self.a + b, self.a),b
foo = Foo(1)
def Calc(b):
return foo.Sum(b)
if __name__ == '__main__':
print(f'original foo id:{id(foo)}')
pool = mp.Pool(processes=2)
b = [0, 1, 2, 3, 5, 6, 7, 8]
out = pool.map(Calc, b)
out.sort(key=lambda x: (x[0],x[-1]))
for result in out:
print(f'pid:{result[0]} b:{result[-1]} {result[1]} {result[2]}')
print(f'{id(foo)}.a is still {foo.a}')
pool.terminate()
...
PS C:\pyprojects> py -m tmp
original foo id:2466513417648
pid:10460 b:1 I am 2729330535728, a: before=1 | after=2 (3, 2)
pid:10460 b:3 I am 2729330535728, a: before=2 | after=5 (8, 5)
pid:10460 b:6 I am 2729330535728, a: before=5 | after=2 (8, 2)
pid:10460 b:8 I am 2729330535728, a: before=2 | after=2 (10, 2)
pid:13100 b:0 I am 2799588470064, a: before=1 | after=1 (1, 1)
pid:13100 b:2 I am 2799588470064, a: before=1 | after=6 (8, 6)
pid:13100 b:5 I am 2799588470064, a: before=6 | after=8 (13, 8)
pid:13100 b:7 I am 2799588470064, a: before=8 | after=0 (7, 0)
2466513417648.a is still 1
PS C:\pyprojects>