不能多进程用户定义的代码 - 不能 pickle

can't multiprocess user defined code - cannot pickle

我尝试在我的任务中使用多处理,这通常意味着进行一些计算,然后将结果传回。问题在于定义计算的代码是由用户定义的,它是在执行之前从字符串编译而来的。当在主进程中为 运行 时,使用 exec()eval()compile() 等非常有效。以下示例仅适用于 f1 函数,不适用于 f2。我收到“无法腌制 class 'code'”。有什么办法解决这个问题吗?例如,以不同方式使用多处理?还是使用其他包?还是一些更底层的东西?不幸的是,由于整个应用程序的设计,将字符串传递给进程然后在进程内部编译对我来说不是一个选项(即代码字符串是 'lost' 并且只有编译版本可用)。

import multiprocessing

def callf(f, a):
    exec(f, {'a': a})

if __name__ == "__main__":
    f = compile("print(a)", filename="<string>", mode="exec")
    callf(f, 10)  # this works
    process = multiprocessing.Process(target=callf, args=(f, 20))  # this does not work
    process.start()
    process.join()

更新:这是另一种尝试,实际上更接近我的实际需要。它会导致不同的错误消息,但也无法 pickle 函数。

import multiprocessing

if __name__ == "__main__":
    source = "def f(): print('done')"
    locals = dict()
    exec(source, {}, locals)
    f = locals['f']
    f()  # this works
    process = multiprocessing.Process(target=f)  # this does not work
    process.start()
    process.join()

pickle 不能序列化代码对象但是 dill can. There is a dill-based fork of multiprocessing called multiprocessing_on_dill 但我不知道它有多好。您也可以只对代码对象进行 dill 编码以使标准的多处理变得快乐。

import multiprocessing
import dill

def callf_dilled(f_dilled, a):
    return callf(dill.loads(f_dilled), a)

def callf(f, a):
    exec(f, {'a': a})

if __name__ == "__main__":
    f = compile("print(a)", filename="<string>", mode="exec")
    callf(f, 10)  # this works
    process = multiprocessing.Process(target=callf_dilled, 
        args=(dill.dumps(f), 20))  # now this works too!
    process.start()
    process.join()