PicklingError : What can cause this error in a function?

PicklingError : What can cause this error in a function?

我有一个函数,其中包含一个 对象列表 、两个 整数列表 和一个 int(一个ID)作为参数,其中returns两个int列表的元组。这个功能很好用,但是当我的 ID 列表变长时,它会花费很多时间。已经在其他项目中使用过multiprocessing,在我看来,这种情况适合使用multiprocessing Pool。

但是,我在启动时遇到错误 _pickle.PicklingError

过去几天我一直在寻找替代方法:我发现 pathos ProcessPool 永远运行,没有任何问题迹象。我已经尝试 ThreadingPool 作为已接受的答案,但它显然不适合我的问题,因为它不使用多个 CPU 并且不会加快进程。

这是我的函数示例,它不是可重现的示例,因为它是针对我的情况的。但我相信该功能非常清楚:它 returns 两个列表的元组,在 for 循环中创建。

def getNormalOnConnectedElements(elem, mapping, idList, node):
    normalZ = []
    eids = []
    for e in mapping[node]:
        if e in idList:
            normalZ.append(elem[e].Normal()[2])
            eids.append(e)
    return normalZ, eids

我试着像往常一样调用它:

with Pool(4) as p:
    # with functools.partial()
    result = p.map(partial(getNormalOnConnectedElements, elemList, mapping, idList), nodeList)
    # or with itertools.repeat()
    result = p.starmap(getNormalOnConnectedElements, zip(repeat(elemList), repeat(mapping), repeat(idList), nodeList))

我确保函数是在顶层定义的,并且调用在 if __name__ == "__main__": 块中。

所以问题是:这个函数中的什么导致 pickle 抛出 _pickle.PicklingError

编辑:

  File "<input>", line 1, in <module>
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2021.2.2\plugins\python-ce\helpers\pydev\_pydev_bundle\pydev_umd.py", line 198, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2021.2.2\plugins\python-ce\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "C:/Users/TLEP6OQM/Documents/Anaconda/PLoad tool/model.py", line 209, in <module>
    allVec = p.map(partial(getNormalOnConnectedElements, elem, allElemIds, mapping), myFilter)
  File "C:\ProgramData\Anaconda3\envs\myenv\lib\multiprocessing\pool.py", line 290, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "C:\ProgramData\Anaconda3\envs\myenv\lib\multiprocessing\pool.py", line 683, in get
    raise self._value
  File "C:\ProgramData\Anaconda3\envs\myenv\lib\multiprocessing\pool.py", line 457, in _handle_tasks
    put(task)
  File "C:\ProgramData\Anaconda3\envs\myenv\lib\multiprocessing\connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "C:\ProgramData\Anaconda3\envs\myenv\lib\multiprocessing\reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
_pickle.PicklingError: Can't pickle <function getNormalOnConnectedElements at 0x00000257E6785620>: attribute lookup getNormalOnConnectedElements on __main__ failed

如果有人偶然发现了这个问题,即使使用非常简单的函数也会发生此错误的原因是因为我 运行 使用 python 脚本的方式。正如 ShadowRanger 在评论中很好地解释的那样,该函数需要在顶层定义。在 PyCharm 中,“运行 Python 控制台中的文件”不只是 运行 它,而是包装了它。

通过 运行 以正确的方式打开文件,或调用 python myscript.py,没有出现错误。