通过python的多处理模块在Pool worker中使用本地内存

时间:2018-10-17 14:57:02

标签: python multiprocessing

我正在努力在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)

这行得通,但我遇到了问题。即,使用管道存储中间结果感觉很愚蠢(可能很慢)。但这也有一个真正的问题,就是我无法通过管道发送任意大的东西,不幸的是,我的应用有时超过了这个大小(和死锁)。

所以,我真正想要的是一个类似于初始化程序的函数,我可以为池中的每个工作程序调用一次,以将其本地结果返回给父进程。我找不到这种功能,但也许有人在这里有个主意?

最后几点注意事项:

  • 我对输入使用全局变量,因为在我的应用程序中输入非常大,并且我不想将其复制到每个进程。由于进程从不向其写入数据,因此我认为不应将其复制(否则我错了吗?)。我乐于接受建议以不同的方式执行此操作,但是请记住,我需要在更改输入时运行此操作(不过,就像上面的示例一样)。
  • 我想避免使用Manager类,因为(据我所知)它引入了同步和锁定,因此在这个问题上完全没有必要。

我能找到的唯一另一个类似的问题是Python's multiprocessing and memory,但他们希望实际处理工人的个人结果,而我不希望工人返回N东西,而只求总价N次,仅返回其本地最佳结果。

我正在使用Python 2.7.15。


tl; dr:是否有一种方法可以在多处理池中为每个工作进程使用本地内存,这样每个工作人员都可以计算局部最优值,而父进程只需要担心找出哪个是最好的?

1 个答案:

答案 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!