反模式:在循环中调用 ray.get 会损害并行性#
TLDR: 避免在循环中调用 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)
在循环中调用 ray.get()#
在调度远程工作后立即调用 ray.get() 时,循环会阻塞直到结果被接收。因此我们最终得到的是顺序处理。相反,我们应该首先调度所有远程调用,这些调用随后会并行处理。在调度工作后,我们可以一次性请求所有结果。
其他与 ray.get() 相关的反模式包括:
不必要的ray.get