Ошибка происходит при сохранении `ActorHandler` в другом актере для последующего использования - PullRequest
0 голосов
/ 01 апреля 2020

Я хочу, чтобы удаленный класс сохранил другой удаленный класс, чтобы он мог вызывать его позже. Следующий код предоставляет пример

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()

Однако этот код не работает; он застревает без каких-либо ошибок. Я знаю, что источником проблемы является функция step в Worker, но я не знаю, почему это неправильно и как это исправить.

1 Ответ

1 голос
/ 05 апреля 2020

Во-первых, обратите внимание, что ray.get является блокирующим вызовом. Это означает, что ваша программа будет заблокирована и не сможет go перейти к следующей строке кода, пока функция ray.get не будет успешно выполнена. (Вы можете предотвратить это, добавив аргумент timeout к функции remote).

Это происходит потому, что l блокируется до тех пор, пока не будет выполнено worker.step.remote (ray.get(worker.step.remote()). Когда вызывается метод worker.step, он пытается вызвать l.p.remote. w будет заблокирован, пока l.p не будет завершено из-за ray.get(self.l.p.remote(self.a). Но, как вы видите, l заблокирован и не может запускать какой-либо код. Это означает, что l.p никогда не будет работать, пока не будет завершено l.step. Вот простая диаграмма для вашего понимания.

enter image description here

Теперь оба работника заблокированы, и l.step.remote никогда не будет выполнено. Это означает, что ваш драйвер (Python скрипт) также заблокирован.

В результате вся программа зависает !!

Тогда как решить эту проблему?

Во-первых, я настоятельно не рекомендую вам использовать шаблон двух классов акторов ждем друг друга. Обычно это плохая модель, даже когда вы пишете другие программы. Это может быть решено, когда программы являются многопоточными или асинхронными.

Если вам действительно нужно использовать этот шаблон, вы можете использовать asyn c actor. Актер Asyn c использует await вместо ray.get, и каждый актер не блокируется, потому что он работает как сопрограмма.

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() 
...