Ray如何处理包依赖?是否要求工作节点提前安装全部运行依赖?
关于Ray依赖管理与代码分发的核心问题解答
1. Ray的默认依赖假设
Ray的核心默认运行假设就是:所有工作节点的运行环境已经预先安装了任务需要的全部依赖,和提交任务的驱动节点(比如你运行Jupyter的节点)环境完全一致。如果依赖版本、安装情况不匹配,大概率会抛出导入错误、类/方法不存在等异常。
2. 远程代码的传输机制
被ray.remote装饰的函数/类,会在定义阶段自动通过Ray定制的pickle序列化器完成序列化,第一次调用对应远程函数/actor时,序列化后的代码会被分发到调度到的工作节点,反序列化后执行。
注意:Ray只会传输你定义的远程函数/类本身的代码,不会自动把驱动节点导入的所有模块都打包传输到工作节点。
3. 远程函数的导入规则与模块生命周期
- 远程函数无法直接访问驱动节点已经导入的内容,和本地运行表现不一致。除非你显式把导入的对象作为参数传给远程函数,否则必须在远程函数内部重新导入需要的依赖。
- 导入的模块不会在函数返回后消失:Ray的工作节点上会启动长期运行的worker进程,同一个worker进程内的所有任务共享同一个Python解释器,你第一次在该worker中导入的模块会被Python解释器自动缓存,后续同一个worker处理的任务不需要重复导入,天然支持重量级依赖仅导入一次即可复用的需求。
- 每次远程函数调用不是在独立解释器中运行:默认会复用worker进程的解释器,只有worker进程崩溃或者被Ray资源调度回收时才会销毁。如果需要强制每次任务使用干净的解释器,可以给远程函数添加
@ray.remote(max_calls=1)装饰,让每个任务跑完就销毁对应的worker。
4. ray.put的使用限制
- 你不能用
ray.put上传整个模块,比如ray.put(pytorch)这类操作是无效的。ray.put只能序列化Python对象,无法把驱动节点安装好的完整库序列化后传输到工作节点。如果工作节点没有安装pytorch,就算你在驱动节点把pytorch模块作为参数传给远程函数,反序列化阶段也会直接抛出找不到对应模块的错误。 - 你可以上传基于依赖模块创建的对象(比如pytorch的Tensor、自定义类的实例),前提是工作节点已经安装了对应版本的依赖,否则反序列化会失败。
5. Ray原生依赖同步方案(适配Jupyter交互式场景)
你不需要依赖NFS共享conda环境这类外部方案,Ray自带运行时环境管理能力,完全可以匹配环境动态变更的需求:
你可以在初始化Ray或者定义远程函数的时候指定runtime_env参数,直接声明需要的依赖版本,Ray会自动在工作节点创建对应的临时运行环境,执行任务时自动激活:
# 全局指定所有任务的运行环境 import ray ray.init(runtime_env={ "conda": { "dependencies": ["pytorch=2.0", "torchvision", "numpy=1.24"] } }) # 也可以单独给某个远程函数指定专属环境 @ray.remote(runtime_env={"pip": ["scikit-learn==1.2"]}) def train(): import sklearn return sklearn.__version__
当你的依赖发生升级等变更时,只需要修改runtime_env的配置即可,Ray会自动检测变更,在工作节点重建对应的运行环境,不需要提前批量操作所有节点。
内容的提问来源于stack exchange,提问作者Alex I
相关产品推荐
相关产品推荐

