我有一个线程池,每个线程都应该可以访问一个数组。不幸的是,这没有按照我的想法工作。这是一个最小的代码片段:
#!/usr/bin/python3
import multiprocessing
class MyClass():
shared = []
l = multiprocessing.Lock()
def __init__(self):
with multiprocessing.Pool(processes=2) as pool:
pool.map(self.mythread, range(1,10))
print(self.shared)
def mythread(self, param):
print(param)
self.l.acquire()
self.shared.append(param)
print(self.shared)
self.l.release()
if __name__ == "__main__":
instance = MyClass()
我希望最后一个输出包含所有数字,但事实并非如此,它甚至是空的。此外,似乎我在中间数组状态中丢失了数字。我认为不可能有比赛条件。 输出:
1
[1]
2
[1, 2]
3
[3]
4
[3, 4]
5
[1, 2, 5]
6
[1, 2, 5, 6]
9
7
[1, 2, 5, 6, 9]
[3, 4, 7]
8
[3, 4, 7, 8]
[]
答案 0 :(得分:0)
您所做的不正确。可以使用多个线程,因为它们共享内存,但是多个进程不共享内存!内存被复制到子进程,因此每个进程都有其自己的“共享”数组副本,而主进程具有从未被触及的原始副本。
multiprocessing
模块确实have some facilities to handle shared state,但是请注意,共享对象比普通的python对象要慢。相反,通常使子进程完全独立并使主进程最终重组输出更为容易。
根据您的情况,您可以使用Manager
对象实例化共享列表:
import multiprocessing
class MyClass():
shared = []
l = multiprocessing.Lock()
def __init__(self):
with multiprocessing.Manager() as manager, multiprocessing.Pool(processes=2) as pool:
self.shared = manager.list([])
pool.map(self.mythread, range(1,10))
print(self.shared)
def mythread(self, param):
print(param)
self.l.acquire()
self.shared.append(param)
print(self.shared)
self.l.release()
if __name__ == "__main__":
instance = MyClass()
但这可能会更快:
import multiprocessing
class MyClass():
def __init__(self):
with multiprocessing.Pool(processes=2) as pool:
results = pool.map(self.mythread, range(1,10))
final_result = [x for res in results for x in res]
print(final_result)
def mythread(self, param):
print(param)
# assume that this might return more than one value
return [param, ...]
if __name__ == "__main__":
instance = MyClass()
顺便说一句:如果在map
处应用的functin的结果与其他子过程无关,并且仅具有一个结果,则仅使用map
即可返回值列表你想要的。