Ray function


To parallelize a function with the Ray framework, decorate the function with @ray.remote to run the function remotely. Call the function with .remote() instead of calling it normally. The remote call yields a future that must be fetched with ray.get. The example below compares a parallel Ray function to a standard non-parallel function. A computationally expensive task is simulated by using the sleep() function.

import ray
import time


@ray.remote
def squared(x):
    time.sleep(1)
    y = x**2
    return y


def squared2(x):
    time.sleep(1)
    y = x**2
    return y


def run_ray():
    """
    Execute a Python function in parallel using Ray. Compare elapsed time to
    the non-parallel example `run_noray()`.
    """
    ray.init()

    tic = time.perf_counter()

    lazy_values = [squared.remote(x) for x in range(8)]
    values = ray.get(lazy_values)

    toc = time.perf_counter()

    print(f'Elapsed time {toc - tic:.2f} s')
    print(values)

    ray.shutdown()


def run_noray():
    """
    Execute a Python function in series, not in parallel. Compare elapsed time
    to the Ray parallel example `run_ray()`.
    """
    tic = time.perf_counter()

    values = [squared2(x) for x in range(8)]

    toc = time.perf_counter()

    print(f'Elapsed time {toc - tic:.2f} s')
    print(values)


def main():
    """
    Run the Ray example or the non-Ray example.
    """
    # run_ray()
    run_noray()


if __name__ == '__main__':
    main()

Results from running the above example on a 6-core MacBook Pro are shown below. As expected, the example that uses the parallel Ray function has the fastest elapsed time.

# Results from running the parallel Ray function
Elapsed time 1.02 s
[0, 1, 4, 9, 16, 25, 36, 49]

# Results from running the non-parallel function
Elapsed time 8.02 s
[0, 1, 4, 9, 16, 25, 36, 49]

🐍 Pythonic Programming
by Gavin Wiggins © 2022