故障排除#

本页包含编译图执行的常见问题和解决方案。

限制#

编译图是一个新功能,存在一些限制

  • 调用编译图

    • 只有编译了编译图的进程才能调用它。

    • 编译图有最大在途执行数量。使用 DAG API 时,如果在调用 dag.execute() 时没有足够的资源,Ray 会将任务排队等待稍后执行。Ray 编译图目前不支持超出最大容量的排队。因此,在提交更多执行之前,你可能需要使用 ray.get() 消耗一些结果。作为权宜之计,如果调用时间过长,dag.execute() 会抛出 RayCgraphCapacityExceeded 异常。将来,编译图可能会有更好的错误处理和排队机制。

  • 编译图执行

    • 理想情况下,当 Actor 参与编译图时,你应该尽量不要在该 Actor 上执行其他任务。编译图任务将在后台线程上执行。提交给 Actor 的任何并发任务仍然可以在主线程上执行,但你需要负责与编译图后台线程同步。

    • 目前,Actor 一次只能执行一个编译图。要在同一个 Actor 上执行不同的编译图,必须先 teardown(拆解)当前的编译图。更多详情请参见返回 NumPy 数组

  • 传递和获取编译图结果 (CompiledDAGRef)

    • 编译图结果不能传递给另一个任务或 Actor。将来可能会放宽此限制,但目前,这有助于提高性能,因为后端确切地知道将结果推送到哪里。

    • CompiledDAGRef 调用 ray.get() 最多一次。如果对同一个 CompiledDAGRef 调用两次,将抛出异常。这是因为结果的基础内存可能需要重复用于将来的 DAG 执行。将 ray.get() 限制为每个引用一次简化了内存缓冲区的跟踪。

    • 如果 ray.get() 返回的值是零拷贝反序列化的,则同一 DAG 的后续执行将阻塞,直到该值在 Python 中超出作用域。因此,如果你持有 ray.get() 返回的零拷贝反序列化值,并且试图在编译图超出其最大并发度时执行它,可能会发生死锁。将来会检测到这种情况,但目前你会收到一个 RayChannelTimeoutError。更多详情请参见在使用相同的 Actor 之前明确 teardown

  • 集体操作

    • 对于 GPU 到 GPU 的通信,编译图仅支持点对点传输。集体通信操作即将推出。

请关注未来 Ray 版本中的更多功能: - 支持更好的 DAG 输入排队,以支持同一 DAG 的更多并发执行。 - 支持更多使用 NCCL 的集体操作。 - 支持在同一个 Actor 上执行多个 DAG。 - 通用性能改进。

如果你遇到其他问题,或者有其他反馈或疑问,请在GitHub上提交 issue。有关已知问题的完整列表,请查看 Ray GitHub 上带 compiled-graphs 标签的 issue。

返回 NumPy 数组#

Ray 在可能的情况下会对 NumPy 数组进行零拷贝反序列化。如果你多次执行输出 NumPy 数组的编译图,如果在尝试获取同一个编译图后续执行结果之前,前一次编译图执行输出的 NumPy 数组没有被删除,则可能会遇到问题。这是因为 NumPy 数组会一直保留在编译图的缓冲区中,直到你或 Python 删除它。建议明确删除 NumPy 数组,因为 Python 可能不会像你期望的那样立即对 NumPy 数组进行垃圾回收。

例如,如果 NumPy 数组没有被删除,以下代码示例可能会导致挂起或 RayChannelTimeoutError

import ray
import numpy as np
from ray.dag import InputNode


@ray.remote
class NumPyActor:
    def get_arr(self, _):
        numpy_arr = np.ones((5, 1024))
        return numpy_arr


actor = NumPyActor.remote()
with InputNode() as inp:
    dag = actor.get_arr.bind(inp)
cgraph = dag.experimental_compile()
for _ in range(5):
    ref = cgraph.execute(0)
    result = ray.get(ref)
    # Adding this explicit del would fix any issues
    # del result

在上面的代码片段中,Python 可能不会在循环的每次迭代中对 result 中的 NumPy 数组进行垃圾回收。因此,在尝试获取后续编译图执行结果之前,你应该明确删除 NumPy 数组。

在使用相同的 Actor 之前明确 teardown#

如果你想重用编译图的 Actor,重要的是在使用这些 Actor 之前明确 teardown 编译图。如果不明确拆解编译图,为编译图中的 Actor 创建的资源可能会与这些 Actor 的进一步使用发生冲突。

例如,在以下代码中,Python 可能会延迟垃圾回收,这会触发第一次编译图的隐式拆解。这可能会导致由于上述资源冲突而引发段错误 (segfault)

@ray.remote
class SendActor:
    def send(self, x):
        return x


actor = SendActor.remote()
with InputNode() as inp:
    dag = actor.send.bind(inp)
cgraph = dag.experimental_compile()

# Not adding this explicit teardown before reusing `actor` could cause problems
# cgraph.teardown()

with InputNode() as inp:
    dag = actor.send.bind(inp)
cgraph = dag.experimental_compile()