【问题标题】:Can't pickle local object when multiprocessing with pool.map使用 pool.map 进行多处理时无法腌制本地对象
【发布时间】:2021-04-22 16:25:51
【问题描述】:

我正在尝试将multiprocessing 与python Pool 函数一起使用,使用functools.partial 将几个具有常量值的参数输入到pool.map 命令中(即第一个参数是唯一的变量)。

问题是当我运行代码时出现以下错误,我不知道为什么或如何解决它:

AttributeError: Can't pickle local object 
    'get_MAX_SNR_for_eventdata_file.<locals>.get_SNR_multiprocess'

我不知道为什么它不能腌制一个物体。这是代码(在顶级函数中):

def get_SNR_multiprocess(binning, event_data, energy_interval, tstart, tstop, trigger_time):
    """ This function just changes the order of arguments to be able to use partial"""
    SNR=get_max_SNR_est(event_data, energy_interval, binning, tstart, tstop, trigger_time)
    return SNR

pool=multiprocessing.Pool(processes=4)

for i in range(len(energybands)-1):
    energy_interval=[energybands[i],energybands[i+1]]
    partial_func=partial(get_SNR_multiprocess, event_data=event_data, 
                         energy_interval=energy_interval, tstart=tstart, tstop=tstop, 
                         trigger_time=trigger_time)
    SNRlist=pool.map(partial_func,timescales)
pool.close()

根据What can be pickled?,我得到一个提示,这个问题可能与只有在模块顶层定义的函数才能被腌制这一事实有关。但是,我无法准确找出我的代码中的问题,或者如何解决它。

代码中的函数get_max_SNR_est是在同一个脚本中定义的函数,并返回一个值。此函数依赖于同一脚本的其他函数(依赖于另一个函数,依此类推...)。

仅供参考,代码无需使用 for 循环进行多处理即可工作,例如:

SNRlist=[]
for i in range(len(energybands)-1):
    energy_interval=[energybands[i],energybands[i+1]]
    for binning in timescales:
        SNR=get_max_SNR_est(event_data, energy_interval, binning, tstart, tstop, 
                            trigger_time)
        SNRlist.append(SNR)

编辑:我忘了说明我在这里展示的代码已经在一个函数中了。根据@martineau 的评论,我将get_SNR_multiprocessing 函数从上述函数中取出,解决了酸洗问题(见答案)。

【问题讨论】:

  • 问题是因为内部partial() 创建了一个partial object,这显然不会发生在模块的顶层。错误消息显示get_SNR_multiprocess 而不是partial_func 的原因是因为这是partial 赋予该对象的名称(即它“包装”了原始函数)。我不确定如何解决可变数量的partial 对象的问题。
  • @martineau 你的评论帮助我解决了一个问题,通过将get_SNR_multiprocess 从主要功能中取出(我之前没有提到,但现在它已添加到帖子中)。现在,又出现了一个问题
  • 我认为应该删除这个问题并提出一个新问题来解释你的新问题——因为酸洗问题已经解决了(不客气)。
  • 完成。我没有在其他地方发布其他问题,因为我找到了解决方案。感谢您的反馈

标签: python multithreading pickle python-multiprocessing


【解决方案1】:

感谢@martineau 的评论,我找到了解决此问题的方法。正如我稍后在问题的编辑中提到的,我在这里显示的代码已经在一个函数中。我把上面提到的函数get_SNR_multiprocessing去掉了,解决了酸洗的问题。新代码(我在其中显示包含上述代码的函数)如下所示:

def get_SNR_multiprocess(binning, event_data, energy_interval, tstart, tstop, trigger_time):
    """ This function just changes the order of arguments to be able to use functools.partial for multiprocessing"""
    SNR=get_max_SNR_est(event_data, energy_interval, binning, tstart, tstop, trigger_time)
    return SNR

def get_MAX_SNR_for_eventdata_file(event_data, energybands, timescales, tstart, tstop, trigger_time):
    """
    Gives the maximum SNR of all timescales and energybands given for a given event_data file
    """ 
    SNRlist=[]
    for i in range(len(energybands)-1):
        energy_interval=[energybands[i],energybands[i+1]]

        with multiprocessing.Pool(processes=4) as pool:
            partial_func=partial(get_SNR_multiprocess, event_data=event_data, energy_interval=energy_interval, tstart=tstart, tstop=tstop, trigger_time=trigger_time)
            SNRlist=pool.map(partial_func,timescales)

不幸的是,此方法与带有for 循环的原始方法所用时间相同。

【讨论】:

  • 不幸的是,如果由于开销而必须在进程之间交换大量数据,那么多处理通常不会加快速度。 然而在 Python 3.8 中,他们添加了一个 multiprocessing.shared_memory 类,它消除了很多开销(即使用腌制数据以及相关的腌制和解封) - 所以你可能想尝试一下。
猜你喜欢
  • 2010-12-21
  • 2020-09-22
  • 2022-01-02
  • 2021-11-10
  • 1970-01-01
  • 2021-06-17
  • 2019-02-19
  • 2019-03-03
  • 1970-01-01
相关资源
最近更新 更多