实验 5:调试和反模式
Ray 的 API 很容易上手,但性能问题经常来自错误的使用方式。本章列出最常见的几个坑。
反模式 1:循环里 ray.get
运行:
bash
uv run python examples/ray_demos/05_antipatterns.py慢写法:
python
results = []
for i in range(8):
results.append(ray.get(work.remote(i)))快写法:
python
refs = [work.remote(i) for i in range(8)]
results = ray.get(refs)原因:慢写法每次只允许一个任务在执行,破坏了并行性。
反模式 2:任务太细
不要把极小函数拆成 Ray Task:
python
@ray.remote
def add_one(x):
return x + 1如果每个任务只运行几微秒,调度和序列化开销会超过计算本身。
解决方式:
- batch 多个元素。
- 使用向量化库。
- 用 Ray Data 做数据处理。
反模式 3:重复传大对象
慢:
python
refs = [predict.remote(model_weights, batch) for batch in batches]更好:
python
weights_ref = ray.put(model_weights)
refs = [predict.remote(weights_ref, batch) for batch in batches]如果模型要长期驻留在 GPU 上,Actor 可能更好:
python
worker = ModelWorker.remote(model_path)
refs = [worker.predict.remote(batch) for batch in batches]反模式 4:单个 Actor 承担所有流量
Actor 默认串行执行。如果所有请求都发给一个 Actor,很容易排队。
解决方式:
- 创建 Actor pool。
- 按 key 分片。
- 使用 async Actor。
- 把无状态部分改成 Task。
反模式 5:资源声明缺失
GPU 任务必须声明 GPU:
python
@ray.remote(num_gpus=1)
def train(...):
...否则 Ray 可能把多个 GPU 任务调度到同一块 GPU 所在节点,或者把任务调度到没有 GPU 的节点。
Dashboard 调试清单
启动 Ray 程序后,打开 Dashboard。你重点看:
| 页面 | 关注点 |
|---|---|
| Jobs | Driver 是否正常,任务是否失败 |
| Tasks | 任务是否 pending、running、failed |
| Actors | Actor 是否重启、队列是否堆积 |
| Nodes | CPU/GPU 资源是否空闲或耗尽 |
| Objects | Object Store 是否接近满,是否 spill |
| Logs | Worker、Raylet、GCS 错误 |
一套排查顺序
Mini Ray 调试
Mini Ray 提供 ray.metrics():
python
print(ray.metrics())输出包含:
- 提交任务数。
- 完成任务数。
- 失败任务数。
- 当前对象数。
- 资源总量和可用量。
- Actor 数量。
这不是生产级监控,但足以帮助你理解运行时状态。