cloudpickle:在不需要时意外导入我的本地模块

问题描述 投票:0回答:1

在文件 ai2_kit/domain.py 中

def fun(ctx):
    def in_add(a, b):
        print (a+b)

    ctx.executor.run_python_fn(in_add)(1, 2)   # this pass
    ctx.executor.run_python_fn(out_add)(1, 2)  # this failed, the error is: ModuleNotFoundError: No module named 'ai2_kit'

def out_add(a, b):
    print(a+b)

方法

run_python_fn
定义在ai2_kit/executor.py中,基本思想是使用
python -c
在远程机器上执行Python脚本。

    def run_python_script(self, script: str):
        return self.connector.run('python -c {}'.format(shlex.quote(script)))

    def run_python_fn(self, fn: T, python_cmd=None) -> T:
        def remote_fn(*args, **kwargs):
            dumped_fn = base64.b64encode(cloudpickle.dumps(lambda: fn(*args, **kwargs), protocol=pickle.DEFAULT_PROTOCOL)) 
            script = '''import base64,pickle; pickle.loads(base64.b64decode({}))()'''.format(repr(dumped_fn))
            self.run_python_script(script=script, python_cmd=python_cmd)

我不知道为什么当使用当前函数之外的函数时它会导入

ai2_kit
,该方法
out_add
没有任何外部依赖项。有什么方法可以解决这个问题吗?谢谢你!本地和远程Python都是v3.9.

python pickle cloudpickle
1个回答
0
投票

我根据@jasonharper的解释找到了解决办法:

in_add
是普通
pickle
无法处理的东西,因为没有全局定义的名称;
cloudpickle
认识到这一事实,并对实际的函数定义进行编码,而不仅仅是名称。
out_add
是正常的
pickle
可以处理得很好的东西(假设相同的模块可用于执行 unpickling 的程序),所以
cloudpickle
认为它不需要做任何特殊的事情。

只需将

out_add
的定义更改为

def __export_remote_functions():

  def add(a, b):
    return a + b

  def prod(a, b):
    return a * b
  return (add, prod)

(add, prod) = __export_remote_functions()

executor.run_python_fn(add)(1, 2)

现在一切都很好。

对于要远程执行的函数应该这样定义,并且需要确保它们不能直接依赖于本地模块中定义的任何函数或类(全局模块也可以,只需确保它们也安装在远程Python中即可)。

一个好的做法是在您的项目下创建一个专用的

remote
包,并确保包中的所有方法和类都通过这种特殊方式定义,并且不要导入
remote
包之外的任何内容。

© www.soinside.com 2019 - 2024. All rights reserved.