Ray项目新手使用指南:四大核心优化技巧

Ray项目新手使用指南:四大核心优化技巧

ray ray-project/ray: 是一个分布式计算框架,它没有使用数据库。适合用于大规模数据处理和机器学习任务的开发和实现,特别是对于需要使用分布式计算框架的场景。特点是分布式计算框架、无数据库。 ray 项目地址: https://gitcode.com/gh_mirrors/ra/ray

Ray作为一个分布式计算框架,提供了高度灵活且易于使用的API。本文将为初次接触Ray的开发者提供四个关键优化技巧,帮助避免常见性能陷阱。

核心API速览

在深入技巧前,我们先快速了解Ray的几个核心API:

  • ray.init(): 初始化Ray运行时环境
  • @ray.remote: 装饰器,将普通函数/类转换为可在不同进程执行的远程任务或actor
  • .remote(): 后缀操作符,用于调用远程函数或actor方法
  • ray.put(): 将对象存入对象存储并返回其ID
  • ray.get(): 从对象ID获取实际对象(阻塞操作)
  • ray.wait(): 从对象ID列表中返回已就绪和未就绪的对象ID

技巧1:延迟调用ray.get()

Ray的所有远程操作默认都是异步的,立即返回一个代表结果的future对象(对象ID)。过早调用ray.get()会阻塞程序,影响并行度。

错误示范

# 错误:立即获取每个结果,导致顺序执行
results = [ray.get(do_some_work.remote(x)) for x in range(4)]

正确做法

# 正确:先提交所有任务,再统一获取结果
result_ids = [do_some_work.remote(x) for x in range(4)]
results = ray.get(result_ids)  # 此时并行执行

关键点ray.get()是阻塞操作,应尽可能推迟调用,以最大化并行度。

技巧2:避免微任务

将大量微小任务转换为远程调用会导致调度开销主导执行时间,反而比顺序执行更慢。

问题案例

@ray.remote
def tiny_work(x):  # 每个任务仅0.1ms
    time.sleep(0.0001)
    return x

# 10万次微小任务调用,性能反降
result_ids = [tiny_work.remote(x) for x in range(100000)]

优化方案

将多个小任务聚合成一个较大的远程任务:

@ray.remote
def mega_work(start, end):
    return [tiny_work(x) for x in range(start, end)]

# 每1000个小任务聚合成1个大任务
result_ids = [mega_work.remote(x*1000, (x+1)*1000) for x in range(100)]

经验法则:确保每个远程任务至少需要几毫秒执行时间,以分摊调度开销。

技巧3:避免重复传递大对象

当大对象作为参数传递给远程函数时,Ray会自动调用ray.put()将其存入对象存储。重复传递同一大对象会导致不必要的多次复制。

低效做法

a = np.zeros((5000, 5000))  # 大数组
result_ids = [no_work.remote(a) for x in range(10)]  # 每次调用都复制a

高效方案

预先将对象存入存储,传递其ID:

a_id = ray.put(np.zeros((5000, 5000)))  # 只复制一次
result_ids = [no_work.remote(a_id) for x in range(10)]

额外好处:减少对象存储空间占用,避免过早触发对象回收。

技巧4:流水线数据处理

当任务执行时间差异较大时,等待所有任务完成再处理结果会导致效率低下。使用ray.wait()实现流水线处理,可以及时处理已完成的任务。

传统方式的问题

# 等待所有任务完成
data_list = ray.get([do_some_work.remote(x) for x in range(4)])
process_results(data_list)  # 之后统一处理

流水线优化

result_ids = [do_some_work.remote(x) for x in range(4)]
sum = 0
while len(result_ids):
    done_id, result_ids = ray.wait(result_ids)  # 获取一个完成的任务
    sum = process_incremental(sum, ray.get(done_id[0]))  # 立即处理

执行对比

  • 传统方式:总时间 ≈ 最慢任务时间 + 处理所有结果时间
  • 流水线方式:总时间 ≈ 最慢任务时间 + 处理单个结果时间

总结

  1. 延迟获取:尽可能推迟ray.get()调用以保持并行度
  2. 任务聚合:避免微任务,确保每个远程任务有足够工作量
  3. 对象复用:对大对象预先调用ray.put(),传递ID而非对象本身
  4. 流水处理:使用ray.wait()实现结果处理的流水线化

掌握这四个技巧,你就能避开Ray新手最常见的性能陷阱,编写出高效的分布式程序。记住,分布式编程的关键在于最小化通信和协调开销,最大化并行度和资源利用率。

ray ray-project/ray: 是一个分布式计算框架,它没有使用数据库。适合用于大规模数据处理和机器学习任务的开发和实现,特别是对于需要使用分布式计算框架的场景。特点是分布式计算框架、无数据库。 ray 项目地址: https://gitcode.com/gh_mirrors/ra/ray

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁骥治

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值