反模式:在循环中调用 ray.get 会损害并行性#

简而言之: 避免在循环中调用 ray.get(),因为它是一个阻塞调用;仅为最终结果调用 ray.get()

调用 ray.get() 会获取远程执行函数的返回结果。然而,它是一个阻塞调用,这意味着它总是会等待直到请求的结果可用。如果您在循环中调用 ray.get(),循环将不会继续运行,直到对 ray.get() 的调用得到解决。

如果您在同一个循环中也派发了远程函数调用,那么您将完全得不到并行性,因为(由于 ray.get())您会等待前一个函数调用完成,然后在循环的下一次迭代中才派发下一个调用。这里的解决方案是将 ray.get() 的调用与远程函数的调用分开。这样,所有远程函数都会在等待结果之前派发,并可以在后台并行运行。此外,您可以将一个对象引用列表传递给 ray.get(),而不是逐个调用它来等待所有任务完成。

代码示例#

import ray

ray.init()


@ray.remote
def f(i):
    return i


# Anti-pattern: no parallelism due to calling ray.get inside of the loop.
sequential_returns = []
for i in range(100):
    sequential_returns.append(ray.get(f.remote(i)))

# Better approach: parallelism because the tasks are executed in parallel.
refs = []
for i in range(100):
    refs.append(f.remote(i))

parallel_returns = ray.get(refs)
../../_images/ray-get-loop.svg

在循环中调用 ray.get()#

当在调度远程工作后立即调用 ray.get() 时,循环会阻塞直到收到结果。因此,我们最终得到的是顺序处理。相反,我们应该首先调度所有远程调用,然后它们将被并行处理。在调度工作之后,我们可以一次性请求所有结果。

其他与 ray.get() 相关的反模式有