Python中的多处理意外返回None

时间:2017-05-18 15:56:56

标签: python python-3.x parallel-processing multiprocessing nonetype

我正在尝试在python 3.6(Anaconda发行版)中启动多处理。我已经对我的内部函数(数值积分)进行了大量测试,因此我确信它有效。目前给我带来麻烦的是传递适当的范围,因为我得到一些“无”回报。

import multiprocessing
from multiprocessing import Pool

def chunkwise(t, size=2):
    it = iter(t)
    return zip(*[it]*size)

def sint(tupl):
    print('arg = ',tupl)
    #lower = float(tupl[0])
    #upper = float(tupl[1])
    exit()
    #ans = scipy.integrate.quad(int2,lower,upper) 
    #return ans

n_CPUs = 6 

smin = float(10000)
smax = float(np.inf)
smax_spacing = float(2.5*10**12)
srange = np.linspace(smin,smax_spacing,n_CPUs)

srange = np.append(srange,np.inf)
print('length srange = ',len(srange))
filler=[]

for i in range(len(srange)):
    if i == 0:
        filler.append(float(srange[i]))
    elif srange[i] == srange[-1]:
        filler.append(float(srange[i]))
    else:
        filler.append(float(srange[i]))
        filler.append(float(srange[i]))
srange = np.array(filler)
srange = list(chunkwise(srange))

def main():
    pool = Pool(processes=n_CPUs)
    res1 = pool.map(sint,[(smin,float(smin*2)),  (float(smin*2),float(smin*3))])#srange)
    res = sum(res1)
    pool.close()
    pool.join()
    return res

if __name__ =="__main__":
    result = main()

我的一些调试过程可以在这里包含的代码中看到。目前,我只想查看传递给我的sint()函数的参数。当我打印结果时,我得到了结果

arg = (number,bigger number)
None
arg = (number2, bigger number2)
None

为什么这些“无”出现?目前,它们的存在导致溢出/ NaN在代码的非并行化版本中不存在。有没有办法让“无”出现?我尝试检查tupl,lower和upper中是否存在“None”,但Python似乎不想识别这些(不会打印我写的“未检测到”消息)。

任何帮助都将非常感谢!如果需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:3)

一个问题是多处理为您所写的所有内容启动了一个单独的进程,它完全创建了一个单独的Python实例,因此您的代码实际上运行了多次放在全局范围内的所有内容。运行代码将返回

>>> length srange =  7
>>> length srange =  7

对我来说多次。您需要将其他代码移动到单独的函数中,或者只需在def main()内调用它。然而,修复此问题仍然会导致nones,这似乎是由于您实际上没有在smin中的映射函数pool.map中返回任何内容。通常,您的结果将是None个对象(并且总和也不能超过任何对象),但这里存在另一个问题。您的流程实际上并未关闭。

这可能是因为您致电退出,没有退货或任何事情,甚至不是None

您没有调用exit来结束映射功能,请查看multiprocessing以查看示例。只需使用普通函数作为映射器,无需使用系统调用。

即使这不是您想要的,这是一个简单的示例,用您的示例显示实际运行的多处理代码:

编辑:我没有意识到你发布的大部分内容都不是必需的,我鼓励你在发布问题时做出最小的可验证的例子,我已经缩小并改变了我发布的实际集成内容,我还建议您在提出问题并编写自己的代码时使用正确的命名约定,sinttupl不是可用的描述性名称。我在这里所做的是向您展示如何使用您提供的相同scipy集成实用程序在并行中正确执行集成。您可以将integrated_function替换为您自己的函数的代码,它应该可以使用相同的

from multiprocessing import Pool
from scipy import integrate


def integrated_function(x):
    return x ** 2


def integration_process(integration_range):
    print("thread launched, tuple = ", integration_range)
    lower = float(integration_range[0])
    upper = float(integration_range[1])
    y, err = integrate.quad(integrated_function, lower, upper)
    return y


def main():
    # notice how we put this inside this main function
    n_CPUs = 6
    total_integration_range = 60000
    integration_chunks = 6
    integration_step = total_integration_range / integration_chunks
    integration_ranges = [(i * integration_step, (i + 1) * integration_step) for i in range(integration_chunks)]
    pool = Pool(processes=n_CPUs)
    res1 = pool.map(integration_process, integration_ranges)  # srange)
    res = sum(res1)
    print(res)
    pool.close()
    pool.join()
    return res


if __name__ == "__main__":
    result = main()
    # thread launched, tuple = (0, 10000)
    # thread launched, tuple = (10000, 20000)
    # thread launched, tuple = (20000, 30000)
    # thread launched, tuple = (30000, 40000)
    # thread launched, tuple = (40000, 50000)
    # thread launched, tuple = (50000, 60000)
    # 72000000000000.0

如果您的功能足够复杂并且集成足够大,则多处理的开销应该足够低以使其更快,请注意在线程中打印导致您不想要的减速,所以外面的调试我鼓励你不要打印。

编辑:由于他们想要进行无限集成,我还会在这里发布我对代码的想法和补充,而不是在评论中留下它。

从技术上讲,即使具有无限的积分范围,你实际上并没有无限积分,近似无限积分的具体数值方法超出了这个问题的范围,但是因为scipy.ntegrate.quad是一个用途{{3} }执行它的集成(因此名称' quad'),它修复了这个问题,可以将np.inf作为约束。不幸的是,我不知道如何保证与此界限的连续性能,可能需要比其他所有集成更长的时间才能完成,或者可能需要更少的时间,这意味着将工作分成相等的块变得更难。但是,您只需要更改积分范围的最后一个边界,以包括该范围内的无穷大。

这种变化看起来像这样:

integration_ranges = [(i * integration_step, (i + 1) * integration_step) for i in range(integration_chunks)]
# we take the last element of the array, and all but the last element of the tuple, 
# and make a new tuple with np.inf as the last element
integration_ranges[-1] = integration_ranges[-1][:-1] + (np.inf,)

执行此操作后,您的最后一个边界应该受无穷大限制,因此您的总积分范围实际上为0 - > inf,即使total_integration_range不是无穷大