将 ActorHandler 保存在另一个 actor 中供以后使用时发生错误

Error happens when keeping an `ActorHandler` in another actor for later use

我想要一个遥控器 class 保留另一个遥控器 class 以便以后可以调用它。下面的代码提供了一个例子

import ray

ray.init()
@ray.remote
class Worker:
    def __init__(self):
        self.a = 1
        self.l = None

    def set(self, learner):
        self.l = learner

    def step(self):
        x = ray.get(self.l.p.remote(self.a))
        return x

@ray.remote
class Learner:
    def __init__(self):
        self.a = 3

    def step(self, worker):
        print(ray.get(worker.step.remote()))

    def p(self, a):
        return a + self.a

l = Learner.remote()
w = Worker.remote()
w.set.remote(l)
ray.get(l.step.remote(w))
ray.shutdown()

然而,这段代码不起作用;它卡住了而没有发出任何错误。我知道问题的根源来自Worker中的step函数,但我不知道为什么会出错,也不知道如何解决。

首先,请注意 ray.get 是一个阻塞调用。这意味着您的程序将被阻塞,并且在 ray.get 函数成功之前无法转到下一行代码。 (您可以通过向 remote 函数添加 timeout 参数来防止这种情况发生)。

发生这种情况是因为 l 被阻止,直到 worker.step.remote 完成 (ray.get(worker.step.remote())。当调用 worker.step 方法时,它会尝试调用 l.p.remote。由于 ray.get(self.l.p.remote(self.a)w 将被阻塞,直到 l.p 完成。但是正如您所看到的,l 被阻止并且不能 运行 任何代码。这意味着 l.p 永远不会 运行 直到 l.step 完成。这是一个简单的图表供您理解。

现在两个工人都被阻止了,l.step.remote永远不会完成。这意味着您的驱动程序(Python 脚本)也被阻止了。

结果整个程序挂了!!

那这个问题怎么解决呢?

首先,我强烈建议您不要使用两个演员 类 互相等待的模式。这通常是一个糟糕的模式,即使您正在编写其他程序也是如此。当程序是多线程或者异步的时候可以解决这个问题

如果你真的需要使用这个模式,你可以使用async actor。异步 actor 使用 await 而不是 ray.get,并且每个 actor 都不会被阻塞,因为它们 运行ning 作为协程。

https://ray.readthedocs.io/en/latest/async_api.html

EX)

import ray

ray.init()
@ray.remote
class Worker:
    def __init__(self):
        self.a = 1
        self.l = None

    def set(self, learner):
        self.l = learner

    async def step(self):
        x = await self.l.p.remote(self.a)
        return x

@ray.remote
class Learner:
    def __init__(self):
        self.a = 3

    async def step(self, worker):
        print(await worker.step.remote())

    async def p(self, a):
        return a + self.a

l = Learner.remote()
w = Worker.remote()
w.set.remote(l)
await l.step.remote(w)
# ray.shutdown()