I came across this problem while trying to add a test for recursive remote functions. I think the problem occurs because our testing paradigm requires defining remote functions inside of regular functions.
Defining a remote function inside a regular function works.
def f():
@ray.remote([int], [int])
def g(x):
return x
return ray.get(g(0))
f() # prints 0
Defining a recursive remote function works.
@ray.remote([int], [int])
def factorial(n):
if n == 0:
return 1
return n * ray.get(factorial(n - 1))
ray.get(factorial(2)) # prints 2
Calling a recursive remote function from another remote function works.
@ray.remote([int], [int])
def getfactorial(n):
return ray.get(factorial(n))
ray.get(getfactorial(2)) # prints 2
However, defining a recursive remote function inside of a regular function seems to note work.
def getfact():
@ray.remote([int], [int])
def fact(n):
if n == 0:
return 1
return n * ray.get(fact(n - 1))
Calling getfact() fails with
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/Users/rkn/Workspace/ray/scripts/shell.py in <module>()
----> 1 getfact()
/Users/rkn/Workspace/ray/scripts/shell.py in getfact()
1 def getfact():
----> 2 @ray.remote([int], [int])
3 def fact(n):
4 if n == 0:
5 return 1
/Users/rkn/Workspace/ray/lib/python/ray/worker.pyc in remote_decorator(func)
840 func.__globals__[func.__name__] = func_call # Allow the function to reference itself as a global variable
841 try:
--> 842 to_export = pickling.dumps((func, arg_types, return_types, func.__module__))
843 finally:
844 # Undo our changes
/Users/rkn/Workspace/ray/lib/python/ray/pickling.pyc in dumps(obj)
17 def dumps(obj):
18 stringio = cloudpickle.StringIO()
---> 19 dump(obj, stringio)
20 return stringio.getvalue()
21
/Users/rkn/Workspace/ray/lib/python/ray/pickling.pyc in dump(obj, file, protocol)
13
14 def dump(obj, file, protocol=2):
---> 15 return BetterPickler(file, protocol).dump(obj)
16
17 def dumps(obj):
/Users/rkn/anaconda/lib/python2.7/site-packages/cloudpickle/cloudpickle.pyc in dump(self, obj)
105 self.inject_addons()
106 try:
--> 107 return Pickler.dump(self, obj)
108 except RuntimeError as e:
109 if 'recursion' in e.args[0]:
/Users/rkn/anaconda/lib/python2.7/pickle.pyc in dump(self, obj)
222 if self.proto >= 2:
223 self.write(PROTO + chr(self.proto))
--> 224 self.save(obj)
225 self.write(STOP)
226
/Users/rkn/anaconda/lib/python2.7/pickle.pyc in save(self, obj)
284 f = self.dispatch.get(t)
285 if f:
--> 286 f(self, obj) # Call unbound method with explicit self
287 return
288
/Users/rkn/anaconda/lib/python2.7/pickle.pyc in save_tuple(self, obj)
566 write(MARK)
567 for element in obj:
--> 568 save(element)
569
570 if id(obj) in memo:
/Users/rkn/anaconda/lib/python2.7/pickle.pyc in save(self, obj)
284 f = self.dispatch.get(t)
285 if f:
--> 286 f(self, obj) # Call unbound method with explicit self
287 return
288
/Users/rkn/anaconda/lib/python2.7/site-packages/cloudpickle/cloudpickle.pyc in save_function(self, obj, name)
203 or getattr(obj.__code__, 'co_filename', None) == '<stdin>'
204 or themodule is None):
--> 205 self.save_function_tuple(obj)
206 return
207 else:
/Users/rkn/Workspace/ray/lib/python/ray/pickling.pyc in save_function_tuple(self, func)
44 class BetterPickler(CloudPickler):
45 def save_function_tuple(self, func):
---> 46 code, f_globals, defaults, closure, dct, base_globals = self.extract_func_data(func)
47
48 self.save(_fill_function)
/Users/rkn/anaconda/lib/python2.7/site-packages/cloudpickle/cloudpickle.pyc in extract_func_data(self, func)
315
316 # process closure
--> 317 closure = [c.cell_contents for c in func.__closure__] if func.__closure__ else []
318
319 # save the dict
ValueError: Cell is empty
I came across this problem while trying to add a test for recursive remote functions. I think the problem occurs because our testing paradigm requires defining remote functions inside of regular functions.
Defining a remote function inside a regular function works.
Defining a recursive remote function works.
Calling a recursive remote function from another remote function works.
However, defining a recursive remote function inside of a regular function seems to note work.
Calling
getfact()fails with