我正在努力在python中实现随机算法。由于这涉及多次(例如说N次)执行相同的操作,因此自然而然地并行化了,我想利用它。更具体地说,我想在CPU的所有内核上分配N个迭代。有问题的问题涉及计算某个最大值,因此每个工人都可以计算自己的最大值,然后仅将其报告给父进程,然后该父进程只需从少数几个局部最大值中找出全局最大值即可。
令人惊讶的是,这似乎并不是多处理模块的预期用例,但是我不确定是否还有其他方法。经过一番研究,我想出了以下解决方案(在与结构上相同的列表中找到最大值的玩具问题):
import random
import multiprocessing
l = []
N = 100
numCores = multiprocessing.cpu_count()
# globals for every worker
mySendPipe = None
myRecPipe = None
def doWork():
pipes = zip(*[multiprocessing.Pipe() for i in range(numCores)])
pool = multiprocessing.Pool(numCores, initializeWorker, (pipes,))
pool.map(findMax, range(N))
results = []
# collate results
for p in pipes[0]:
if p.poll():
results.append(p.recv())
print(results)
return max(results)
def initializeWorker(pipes):
global mySendPipe, myRecPipe
# ID of a worker process; they are consistently named PoolWorker-i
myID = int(multiprocessing.current_process().name.split("-")[1])-1
# Modulo: When starting a second pool for the second iteration of doWork() they are named with IDs 5-8.
mySendPipe = pipes[1][myID%numCores]
myRecPipe = pipes[0][myID%numCores]
def findMax(count):
myMax = 0
if myRecPipe.poll():
myMax = myRecPipe.recv()
value = random.choice(l)
if myMax < value:
myMax = value
mySendPipe.send(myMax)
l = range(1, 1001)
random.shuffle(l)
max1 = doWork()
l = range(1001, 2001)
random.shuffle(l)
max2 = doWork()
return (max1, max2)
这行得通,但我遇到了问题。即,使用管道存储中间结果感觉很愚蠢(可能很慢)。但这也有一个真正的问题,就是我无法通过管道发送任意大的东西,不幸的是,我的应用有时超过了这个大小(和死锁)。
所以,我真正想要的是一个类似于初始化程序的函数,我可以为池中的每个工作程序调用一次,以将其本地结果返回给父进程。我找不到这种功能,但也许有人在这里有个主意?
最后几点注意事项:
我能找到的唯一另一个类似的问题是Python's multiprocessing and memory,但他们希望实际处理工人的个人结果,而我不希望工人返回N东西,而只求总价N次,仅返回其本地最佳结果。
我正在使用Python 2.7.15。
tl; dr:是否有一种方法可以在多处理池中为每个工作进程使用本地内存,这样每个工作人员都可以计算局部最优值,而父进程只需要担心找出哪个是最好的?
答案 0 :(得分:0)
您可能对此有点思考。
通过使您的辅助函数(在本例中为echo
)实际上返回一个值而不是传递值,您可以存储调用findMax
的结果-毕竟,它只是map的并行变体!它将在输入列表上映射一个函数,并返回该函数调用的结果列表。
最简单的例子说明了我的观点,紧随您的“分布式最大值”例子:
pool.map()
这将返回import multiprocessing
# [0,1,2,3,4,5,6,7,8]
x = range(9)
# split the list into 3 chunks
# [(0, 1, 2), (3, 4, 5), (6, 7, 8)]
input = zip(*[iter(x)]*3)
pool = multiprocessing.Pool(2)
# compute the max of each chunk:
# max((0,1,2)) == 2
# max((3,4,5)) == 5
# ...
res = pool.map(max, input)
print(res)
。
请注意,发生了一些不可思议的事情:我使用内置的[2, 5, 8]
函数,该函数期望可迭代对象作为输入。现在,如果我仅在简单的整数列表(例如max()
)上pool.map
,将导致调用range(9)
,max(0)
等。-不太有用,嗯?取而代之的是,我将列表分成多个块,这样在映射时非常有效,现在我们映射到一个元组列表,从而在每次调用时将一个元组馈送到max(1)
。
所以也许你必须:
PS:您写了一个很棒的第一个问题!谢谢,很高兴阅读它:)欢迎使用StackOverflow!