0

I have three files as follows

""" main.py """
import time
import ray

class LocalBuffer(dict):
    def __call__(self):
        return self

@ray.remote
class Worker():
    def __init__(self, learner):
        self.local = LocalBuffer()
        self.learner = learner

    def sample(self):
        for i in range(10):
            self.local.update({
                'state': [1, 2, 3]
            })
            print(self.local)
            self.learner.update_buffer.remote(self.local)

@ray.remote
class Learner():
    def __init__(self):
        self.buffer = {}

    def update_buffer(self, local_buffer):
        print(local_buffer)
        self.buffer['state'] = local_buffer['state']

ray.init()

learner = Learner.remote()
worker = Worker.remote(learner)

worker.sample.remote()

time.sleep(10)

The above code will work fine if I remove all code related to ray. If not, something wrong happens. The error message says there is no state in local_buffer in update_buffer. I know that the error arises because of LocalBuffer defined in worker.py -- If I define Worker.local as a built-in dict, everything will be fine. But why can't I use LocalBuffer? I do need it here and I have no idea how to make it work.

Update

I see where the problem is. The reason is that worker and learner are in different processes. And a user-defined object such as self.local cannot be passed between processes. For this specific problem, I can get rid of the problem by casting self.local to dict when self.local is passed to self.learner.update_buffer. I've tried to import LocalBuffer in learner.py, but it did not work. Maybe I have to learn more about multiprocessing to figure it out. I'll be very grateful if anyone is willing to fill me in some useful information.

Maybe
  • 2,129
  • 5
  • 25
  • 45

1 Answers1

0

We have to make LocalBuffer a ray actor in order to make it work. The following code works as desired.

import ray

@ray.remote
class LocalBuffer(dict):
    # have to redefine these functions in order to make it work with ray
    def __getitem__(self, k):
        return super().__getitem__(k)

    def update(self, d):
        super().update(d)

    def __call__(self):
        # cannot return self since self is a ray actor
        return dict(super().items())


@ray.remote
class Worker():
    def __init__(self, learner):
        self.local = LocalBuffer.remote()
        self.learner = learner

    def sample(self):
        for i in range(10):
            id = self.local.update.remote({
                'state': [1, 2, 3]
            })
            print(ray.get(self.local.__call__.remote()))
            self.learner.update_buffer.remote(self.local)


@ray.remote
class Learner():
    def __init__(self):
        self.buffer = {}

    def update_buffer(self, local_buffer):
        print(ray.get(local_buffer.__call__.remote()))
        self.buffer['state'] = ray.get(local_buffer.__getitem__.remote('state'))
        print('learner buffer', self.buffer)

ray.init()

learner = Learner.remote()
worker = Worker.remote(learner)

ray.get(worker.sample.remote())
Maybe
  • 2,129
  • 5
  • 25
  • 45