Во-первых, обратите внимание, что 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
. Вот простая диаграмма для вашего понимания.
Теперь оба работника заблокированы, и 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()