Antipattern: Closure capture of large / unserializable object

TLDR: Be careful when using large objects in @ray.remote functions or classes.

When you define a ray.remote function or class, it is easy to accidentally capture large (more than a few MB) objects implicitly in the function definition. This can lead to slow performance or MemoryError when attempting to define the function, since Ray is not designed to handle serialized functions or classes that are very large.

For such large objects, there are a couple options to resolve this problem: - Use ray.put to put the object in the Ray object store, and then use ray.get to get a view of the object within the task (“better approach #1” below) - Create the object inside the task instead of in the driver script by passing a lambda method (“better approach #2”) - The second method is the only option available for unserializable objects.

Code example

Antipattern:

# Create a 838 MB array, verify via: sys.getsizeof(big_array)
big_array = np.zeros(100 * 1024 * 1024)

@ray.remote
def f():
    return len(big_array) # big_array is serialized along with f!

ray.init()
ray.get(f.remote())

Better approach #1:

big_array = ray.put(np.zeros(100 * 1024 * 1024))

@ray.remote
def f():
    return len(ray.get(big_array))

ray.init()
ray.get(f.remote())

Better approach #2:

array_creator = lambda: np.zeros(100 * 1024 * 1024)

@ray.remote
def f():
    array = array_creator()
    return len(array)

ray.init()
ray.get(f.remote())