Python 多进程 - 就是搞不懂
我花了一些时间想弄明白多进程的概念,但有些细节对我这个新手来说还是很难理解。我能让一个进程池返回一个简单的整数,但如果函数的返回结果不是那么简单,比如我在网上找到的例子(甚至在官方文档里),那些例子都让我觉得很晦涩。
这里有一个我想让它正常工作的例子。但是,我就是无法让它按预期工作,我相信一定有简单的原因。我可能需要使用队列、共享内存或者管理器,但我看了很多遍文档,还是搞不清楚这些到底是什么意思,具体是干什么的。到目前为止,我唯一能理解的就是进程池的功能。
另外,我在使用一个类,因为我需要避免使用全局变量,就像在这个问题的回答里提到的那样。
import random
class thisClass:
def __init__(self):
self.i = 0
def countSixes(myClassObject):
newNum = random.randrange(0,10)
#print(newNum) #this proves the function is being run if enabled
if newNum == 6:
myClassObject.i += 1
if __name__ == '__main__':
import multiprocessing
pool = multiprocessing.Pool(1) #use one core for now
counter = thisClass()
myList = []
[myList.append(x) for x in range(1000)]
#it must be (args,) instead of just i, apparently
async_results = [pool.apply_async(countSixes, (counter,)) for i in myList]
for x in async_results:
x.get(timeout=1)
print(counter.i)
有没有人能用简单易懂的方式解释一下我需要做什么,这样我才能明白我缺少了什么,以及这些东西是干什么的?
1 个回答
12
我花了一些时间才明白你想要实现的效果。问题出在多进程的工作方式上。简单来说,你需要用一种函数式的编程风格来写你的程序,而不是像现在这样依赖副作用。
现在,你把对象发送到池子里去修改,但从 countSixes
函数里什么也没返回。这在多进程中是行不通的,因为为了绕过 全局解释器锁,多进程会创建一个 副本 的 counter
,并把它发送到一个 全新的解释器。所以当你增加 i
的值时,实际上是在增加 i
的一个 副本,然后因为你什么也不返回,所以这个副本就被丢弃了!
要实现一些有用的功能,你必须从 countSixes
返回一些东西。这里有一个简化版的代码,做的事情和你想要的类似。我保留了一个参数,只是为了展示你应该怎么做,但其实这个函数可以不带参数。
import random
def countSixes(start):
newNum = random.randrange(0,10)
if newNum == 6:
return start + 1
else:
return start
if __name__ == '__main__':
import multiprocessing
pool = multiprocessing.Pool(1) #use one core for now
start = 0
async_results = [pool.apply_async(countSixes, (start,)) for i in range(1000)]
print(sum(r.get() for r in async_results))