Ray:评估代码性能

本文档介绍了如何使用Ray评估和优化代码性能,通过基础分析、Python时间戳测试、Line Profiler、CProfile和Ray时间轴可视化来识别性能瓶颈。文中展示了不同循环方式对性能的影响,强调了避免在并行化代码中不必要的ray.get调用以提高效率。
摘要由CSDN通过智能技术生成

本文档适用于想要了解如何在Ray上运行时评估其代码性能的Ray用户。分析代码的性能对于确定性能瓶颈或找出可能无法正确并行化的代码的位置非常有用。如果你有兴趣查明为什么你的Ray应用程序可能无法实现预期的加速,仔细阅读本文。

 

一个基础分析示例

尝试分析一个简单的例子,并比较编写简单循环的不同方式会如何影响性能。

作为计算密集且可能运行比较慢的函数的代表,我们将远程函数定义为只睡眠0.5秒:

import ray
import time
# Our time-consuming remote function
@ray.remote
def func():
    time.sleep(0.5)

在我们的示例中,我们希望将远程函数func()调用五次,并将每个调用的结果存储到列表中。 为了比较以不同方式循环调用我们的远程函数的性能,我们可以在driver脚本上将每个循环版本定义为单独函数。

 

对于第一个版本ex1,循环的每次迭代都会调用远程函数,然后调用ray.get以尝试将当前结果存储到列表中,如下所示:

# This loop is suboptimal in Ray, and should only be used for the sake of this example
def ex1():
    list1 = []
    for i in range(5):
        list1.append(ray.get(func.remote()))

 

对于第二个版本ex2,循环的每次迭代都会调用远程函数,并将其存储到列表中,而不是每次调用ray.get。循环结束后使用ray.get,准备处理func()的结果:

# This loop is more proper in Ray
def ex2():
    list2 = []
    for i in range(5):
        list2.append(func.remote())
    ray.get(list2)

 

最后,对于一个不可如此并行化的示例,创建第三个版本ex3,其中driver必须在每次调用远程函数func()之间调用本地函数:

# A local function executed on the driver, not on Ray
def other_func():
    time.sleep(0.3)
def ex3():
    list3 = []
    for i in range(5):
        other_func()
        list3.append(func.remote())
    ray.get(list3)

 

使用Python的时间戳测试时间性能

合理地检查三个循环函数性能的一种方法是简单地计算完成每个循环所需的时间。我们可以使用python的内置时间模块来完成这个任务。

time模块包含一个有用的time()函数,它在调用时以unix时间返回当前时间戳。我们可以创建一个通用的函数装饰器,在每个循环函数之前和之后调用time()来打印每个循环总体占用的时间:

# This is a generic wrapper for any driver function you want to time
def time_this(f):
    def timed_wrapper(*args, **kw):
        start_time = time.time()
        result = f(*args, **kw)
        end_time = time.time()

        # Time taken = end_time - start_time
        print('| func:%r args:[%r, %r] took: %2.4f seconds |' % \
              (f.__name__, args, kw, end_time - start_time))
        return result
    return timed_wrapper

为了每次调用循环函数ex1()时总是打印出循环运行了多长时间,我们可以用函数装饰器调用time_this包装器。这可以类似地对函数ex2()和ex3()进行:

@time_this  # Added decorator
def ex1():
    list1 = []
    for i in range(5):
        list1.append(ray.get(func.remote()))
def main():
    ray.init()
    ex1()
    ex2()
    ex3()
if __name__ == "__main__":
    main()

然后,运行这三个循环应该产生类似于这样的输出:

| func:'ex
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值