ray 依赖分发

c 复制代码
如果你问的是 **Ray(Python 分布式计算框架)里的代码怎么发到 worker 节点执行**,可以分成两层理解:

## 1. `@ray.remote` 函数/Actor 本身怎么分发?

典型代码:

```python
import ray

ray.init(address="auto")

@ray.remote
def f(x):
    return x + 1

ref = f.remote(1)
print(ray.get(ref))

Ray 的大致流程是:

  1. Driver 进程里定义 @ray.remote 函数或 Actor。
  2. 第一次调用 .remote() 时,Ray 会把这个函数/类序列化。
  3. Ray 把序列化后的函数/类定义放到集群的 GCS / internal KV 里。
  4. 被调度到某个节点上的 worker 通过函数描述符拿到这段序列化代码。
  5. worker 反序列化后执行任务。

Ray 官方的 task lifecycle 文档里说明,RemoteFunction 会把底层函数 pickle 成字节,并存到 GCS key-value store,远端 executor 再取出、反序列化并执行。[1](#1)

Ray 的序列化基于 Pickle protocol 5,并借助 cloudpickle 支持 lambda、嵌套函数、动态类等 Python 对象。[2](#2)

2. 你的项目代码、依赖包怎么分发?

这是更容易踩坑的地方。

Ray 不会默认把你本地整个项目目录自动同步到所有节点@ray.remote 函数本身可以被序列化,但它里面 import 的模块、配置文件、模型文件、依赖库等,worker 节点也必须能访问。

通常有几种方式:


方式 A:用 runtime_env={"working_dir": ...} 分发项目目录

例如:

python 复制代码
ray.init(
    address="auto",
    runtime_env={
        "working_dir": ".",
        "pip": ["numpy", "pandas"]
    }
)

含义是:

  • 把当前目录作为运行目录分发到 worker;
  • worker 执行 task/actor 时可以 import 这个目录里的代码;
  • pip 字段用于安装 Python 依赖。

Ray 官方文档里 working_dir 被描述为本地路径或远程 URI,Ray 会把它解包到每个 task/actor 的工作目录中。[3](#3)


方式 B:用 runtime_env={"py_modules": [...]} 分发 Python 模块

例如:

python 复制代码
ray.init(
    address="auto",
    runtime_env={
        "py_modules": ["./my_package"]
    }
)

适合分发某个 Python package。Ray 会把这些模块加入 worker 的 PYTHONPATH。官方 API 文档说明,py_modules 可以是本地路径或远程 URI,Ray 会解包并插入 worker 的 PYTHONPATH[3](#3)


方式 C:把代码放到远程 URI

例如:

python 复制代码
ray.init(
    address="auto",
    runtime_env={
        "working_dir": "s3://my-bucket/my_project.zip"
    }
)

或者:

yaml 复制代码
runtime_env:
  working_dir: "https://github.com/xxx/project/archive/HEAD.zip"

这种方式更适合生产环境,因为不依赖 driver 本地机器上传代码。Ray Serve 文档也建议生产环境可以把代码打进镜像,或者用 runtime_env 指向远程存储中的代码。[4](#4)


方式 D:直接把代码和依赖打进镜像

生产环境最稳的方式通常是:

Dockerfile 复制代码
FROM rayproject/ray:latest

COPY . /app
WORKDIR /app

RUN pip install -r requirements.txt

然后整个 Ray 集群都用这个镜像启动。

优点:

  • 启动更稳定;
  • 不需要每次 job 提交都上传代码;
  • 依赖版本一致;
  • 更适合 Kubernetes / KubeRay / 生产部署。

3. 参数和返回值怎么分发?

函数代码是一回事,任务参数和返回值是另一回事。

例如:

python 复制代码
@ray.remote
def g(arr):
    return arr.sum()

调用:

python 复制代码
ref = g.remote(big_array)

Ray 会把参数序列化后放入对象存储。Ray 文档说明,Ray 使用 Plasma object store 在进程和节点之间高效传输对象;每个节点有自己的 object store,对象不会自动广播到所有节点,而是在其他 task/actor 请求时才传输。[2](#2)

所以:

  • 小参数会随 task 提交;
  • 大对象通常进入 Ray object store;
  • 跨节点需要时才拉取;
  • 返回值也是通过 ObjectRef 引用。

4. 一个直观总结

可以理解成:

text 复制代码
Driver
  |
  | 1. 序列化 @ray.remote 函数/Actor
  v
GCS / internal KV
  |
  | 2. worker 拉取函数定义
  v
Worker process

同时:

项目目录 / Python 模块 / pip 依赖
  |
  | 通过 runtime_env 或镜像分发
  v
Worker runtime environment

任务参数 / 返回值
  |
  | 通过 Ray object store 分发
  v
ObjectRef / Plasma store

5. 常见坑

坑 1:只定义了 remote 函数,但 worker 找不到本地模块

比如:

python 复制代码
from my_project.utils import helper

@ray.remote
def f(x):
    return helper(x)

如果 worker 节点没有 my_project,会报 ModuleNotFoundError

解决:

python 复制代码
ray.init(
    address="auto",
    runtime_env={"working_dir": "."}
)

或者把 my_project 安装成包:

python 复制代码
ray.init(
    address="auto",
    runtime_env={"pip": ["my_project==0.1.0"]}
)

坑 2:把大对象放进闭包

不要这样:

python 复制代码
big_model = load_model()

@ray.remote
def infer(x):
    return big_model(x)

这样 big_model 可能会跟函数一起被序列化,造成巨大开销。

更好的方式:

python 复制代码
model_ref = ray.put(load_model())

@ray.remote
def infer(model, x):
    return model(x)

ref = infer.remote(model_ref, data)

或者用 Actor 持有模型:

python 复制代码
@ray.remote
class ModelWorker:
    def __init__(self):
        self.model = load_model()

    def infer(self, x):
        return self.model(x)

坑 3:开发环境和生产环境混用

开发时可以用:

python 复制代码
runtime_env={"working_dir": "."}

生产时更推荐:

text 复制代码
Docker image + fixed requirements.txt / lockfile

这样可复现性更好。


简短结论

Ray 的代码分发可以概括为:

  1. @ray.remote 函数/Actor:Ray 用 pickle/cloudpickle 序列化后放到 GCS,worker 拉取后执行。
  2. 项目源码:不会默认全量同步,需要用 runtime_env["working_dir"]runtime_env["py_modules"]、远程 zip URI,或打进 Docker 镜像。
  3. Python 依赖:通过 runtime_env["pip"]condauv,或镜像安装。
  4. 参数和返回值:通过 Ray object store / ObjectRef 分发,不是代码分发。
复制代码

  1. Ray Task Lifecycle - official docs ↩︎

  2. Ray Serialization - official docs ↩︎ ↩︎

  3. ray.runtime_env.RuntimeEnv - official API docs ↩︎ ↩︎

  4. Ray Serve Handling Dependencies - official docs ↩︎

相关推荐
xywww1684 小时前
大模型 API 选型实战:GPT、Gemini、Claude 接入时该看哪些指标?
运维·服务器·人工智能·python·gpt·langchain
夜雪一千9 小时前
Python enumerate() 函数完整详解:遍历同时获取索引,告别手动计数
服务器·windows·python
能有时光10 小时前
PyTorch KernelAgent 源码解读 ---(4)--- ExtractorAgent
人工智能·pytorch·python
_Jimmy_10 小时前
Python 协程库如何使用以及有哪些使用场景
python
aqi0010 小时前
15天学会AI应用开发(十七)使用LangGraph实现会话记忆功能
人工智能·python·大模型·ai编程·ai应用
第一程序员11 小时前
Rust Agent 子进程执行:Command 之前,先定义输入和超时
python·rust·github
skywalk816311 小时前
设计并实现段言的 C FFI 绑定机制 @Trae
c语言·开发语言·python·编程
weixin_BYSJ198711 小时前
SpringBoot + MySQL 乒乓球运动员信息管理系统项目实战--附源码04954
java·javascript·spring boot·python·django·flask·php
EQUINOX113 小时前
【论文阅读】| MoCo精读
论文阅读·人工智能·python·深度学习·机器学习
用户83562907805113 小时前
使用 Python 自动化 Excel 公式和函数:完整指南
后端·python