Make it possible to use actor definitions within remote functions and other actors. (#587)

* Enable remote function and actor definitions to close over actor definitions.

* Give better error message if actor objects are pickled.

* Add tests for closing over actor definitions.

* Fix linting.
This commit is contained in:
Robert Nishihara
2017-05-24 15:43:32 -07:00
committed by Philipp Moritz
parent bc8b0db13e
commit c647dd5f6c
2 changed files with 49 additions and 47 deletions
+4 -1
View File
@@ -375,7 +375,7 @@ def make_actor(Class, num_cpus, num_gpus):
# The following is needed so we can still access self.actor_methods.
if attr in ["_manual_init", "_ray_actor_id", "_ray_actor_methods",
"_actor_method_invokers", "_ray_method_signatures"]:
return super(NewClass, self).__getattribute__(attr)
return object.__getattribute__(self, attr)
if attr in self._ray_actor_methods.keys():
return self._actor_method_invokers[attr]
# There is no method with this name, so raise an exception.
@@ -385,6 +385,9 @@ def make_actor(Class, num_cpus, num_gpus):
def __repr__(self):
return "Actor(" + self._ray_actor_id.hex() + ")"
def __reduce__(self):
raise Exception("Actor objects cannot be pickled.")
return NewClass
+45 -46
View File
@@ -407,32 +407,31 @@ class ActorNesting(unittest.TestCase):
ray.worker.cleanup()
# TODO(rkn): The test testUseActorWithinActor currently fails with a pickling
# error.
# def testUseActorWithinActor(self):
# # Make sure we can use remote funtions within actors.
# ray.init(num_cpus=10)
#
# @ray.remote
# class Actor1(object):
# def __init__(self, x):
# self.x = x
# def get_val(self):
# return self.x
#
# @ray.remote
# class Actor2(object):
# def __init__(self, x, y):
# self.x = x
# self.actor1 = Actor1(y)
#
# def get_values(self, z):
# return self.x, ray.get(self.actor1.get_val())
#
# actor2 = Actor2(3, 4)
# self.assertEqual(ray.get(actor2.get_values(5)), (3, 4))
#
# ray.worker.cleanup()
def testUseActorWithinActor(self):
# Make sure we can use actors within actors.
ray.init(num_cpus=10)
@ray.remote
class Actor1(object):
def __init__(self, x):
self.x = x
def get_val(self):
return self.x
@ray.remote
class Actor2(object):
def __init__(self, x, y):
self.x = x
self.actor1 = Actor1.remote(y)
def get_values(self, z):
return self.x, ray.get(self.actor1.get_val.remote())
actor2 = Actor2.remote(3, 4)
self.assertEqual(ray.get(actor2.get_values.remote(5)), (3, 4))
ray.worker.cleanup()
def testDefineActorWithinRemoteFunction(self):
# Make sure we can define and actors within remote funtions.
@@ -456,26 +455,26 @@ class ActorNesting(unittest.TestCase):
ray.worker.cleanup()
# This test currently fails with a pickling error.
# def testUseActorWithinRemoteFunction(self):
# # Make sure we can create and use actors within remote funtions.
# ray.init(num_cpus=10)
#
# @ray.remote
# class Actor1(object):
# def __init__(self, x):
# self.x = x
# def get_values(self):
# return self.x
#
# @ray.remote
# def f(x):
# actor = Actor1(x)
# return ray.get(actor.get_values())
#
# self.assertEqual(ray.get(f.remote(3)), 3)
#
# ray.worker.cleanup()
def testUseActorWithinRemoteFunction(self):
# Make sure we can create and use actors within remote funtions.
ray.init(num_cpus=10)
@ray.remote
class Actor1(object):
def __init__(self, x):
self.x = x
def get_values(self):
return self.x
@ray.remote
def f(x):
actor = Actor1.remote(x)
return ray.get(actor.get_values.remote())
self.assertEqual(ray.get(f.remote(3)), 3)
ray.worker.cleanup()
def testActorImportCounter(self):
# This is mostly a test of the export counters to make sure that when an