python 多处理 - OverflowError('cannot serialize a bytes object larger than 4GiB')

python multiprocessing - OverflowError('cannot serialize a bytes object larger than 4GiB')

我们是 运行 使用 multiprocessing 库 (python 3.6) 的脚本,其中一个大 pd.DataFrame 作为参数传递给函数:

from multiprocessing import Pool
import time 

def my_function(big_df):
    # do something time consuming
    time.sleep(50)

if __name__ == '__main__':
    with Pool(10) as p:
        res = {}
        output = {}
        for id, big_df in some_dict_of_big_dfs:
            res[id] = p.apply_async(my_function,(big_df ,))
        output = {u : res[id].get() for id in id_list}

问题是我们从 pickle 库中收到错误。

Reason: 'OverflowError('cannot serialize a bytes objects larger than 4GiB',)'

我们知道 pickle v4 可以序列化更大的对象 question related, link,但我们不知道如何修改 multiprocessing 正在使用的协议。

有人知道该怎么办吗? 谢谢!!

显然有空位 issue about this topic , and there is a few related initiatives described on this particular answer. I Found a way to change the default pickle protocol that is used in the multiprocessing library based on this 。正如评论中指出的那样,此解决方案 仅适用于 Linux 和 OS 多处理库

解决方案:

你先创建一个新的分离模块

pickle4reducer.py

from multiprocessing.reduction import ForkingPickler, AbstractReducer

class ForkingPickler4(ForkingPickler):
    def __init__(self, *args):
        if len(args) > 1:
            args[1] = 2
        else:
            args.append(2)
        super().__init__(*args)

    @classmethod
    def dumps(cls, obj, protocol=4):
        return ForkingPickler.dumps(obj, protocol)


def dump(obj, file, protocol=4):
    ForkingPickler4(file, protocol).dump(obj)


class Pickle4Reducer(AbstractReducer):
    ForkingPickler = ForkingPickler4
    register = ForkingPickler4.register
    dump = dump

然后,您需要在主脚本中添加以下内容:

import pickle4reducer
import multiprocessing as mp
ctx = mp.get_context()
ctx.reducer = pickle4reducer.Pickle4Reducer()

with mp.Pool(4) as p:
    # do something

这可能会解决溢出的问题。

但是,警告,您可能会考虑在做任何事情之前阅读 ,否则您可能会遇到与我相同的错误:

'i' format requires -2147483648 <= number <= 2147483647

(这个错误的原因在上面的中有很好的解释)。长话短说,multiprocessing 使用 pickle 协议通过其所有进程发送数据,如果您已经达到 4gb 限制,那可能意味着您可以考虑将函数重新定义为 "void" 方法而不是 input/output 方法。所有这些 inbound/outbound 数据都会增加 RAM 使用率,可能由于构造(我的情况)而效率低下,最好将所有进程指向同一个对象,而不是为每次调用创建一个新副本。

希望这对您有所帮助。

Pablo 的补充回答

下面的问题可以解决Python3.8,如果你用这个版本没问题python:

'i' format requires -2147483648 <= number <= 2147483647