2020-10-16 10:10:56 -07:00
.. _core-walkthrough:
2020-02-11 23:17:30 -08:00
Ray Core Walkthrough
====================
2019-08-05 23:33:14 -07:00
This walkthrough will overview the core concepts of Ray:
2020-02-11 23:17:30 -08:00
1. Starting Ray
2020-07-30 11:13:38 +08:00
2. Using remote functions (tasks)
3. Fetching results (object refs)
4. Using remote classes (actors)
2019-08-05 23:33:14 -07:00
2020-02-11 23:17:30 -08:00
With Ray, your code will work on a single machine and can be easily scaled to large cluster.
2020-07-31 15:35:43 +08:00
Java demo code in this documentation can be found `here <https://github.com/ray-project/ray/blob/master/java/test/src/main/java/io/ray/docdemo/WalkthroughDemo.java> `__ .
2020-07-30 11:13:38 +08:00
2020-02-11 23:17:30 -08:00
Installation
------------
2020-09-05 10:15:52 +08:00
.. tabs ::
.. group-tab :: Python
To run this walkthrough, install Ray with `` pip install -U ray `` . For the latest wheels (for a snapshot of `` master `` ), you can use these instructions at :ref: `install-nightlies` .
.. group-tab :: Java
2020-09-11 06:40:16 +08:00
To run this walkthrough, add `Ray API <https://mvnrepository.com/artifact/io.ray/ray-api> `_ and `Ray Runtime <https://mvnrepository.com/artifact/io.ray/ray-runtime> `_ as dependencies. Snapshot versions can be found in `sonatype repository <https://oss.sonatype.org/#nexus-search;quick~io.ray> `_ .
2020-02-11 23:17:30 -08:00
2021-03-09 18:03:13 +08:00
Note: To run your Ray Java application, you need to install Ray Python with `pip install -U ray` first. (For Ray Java snapshot versions, install nightly Ray Python wheels.) The versions of Ray Java and Ray Python must match.
2020-02-11 23:17:30 -08:00
Starting Ray
------------
2020-07-30 11:13:38 +08:00
You can start Ray on a single machine by adding this to your code.
.. tabs ::
.. code-tab :: python
import ray
# Start Ray. If you're connecting to an existing cluster, you would use
# ray.init(address=<cluster-address>) instead.
ray.init()
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
...
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
2019-08-05 23:33:14 -07:00
2020-09-05 10:15:52 +08:00
import io.ray.api.Ray;
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
public class MyRayApp {
public static void main(String[] args) {
// Start Ray runtime. If you're connecting to an existing cluster, you can set
2020-09-15 11:13:19 +08:00
// the `-Dray.address=<cluster-address>` java system property.
2020-09-05 10:15:52 +08:00
Ray.init();
2020-07-30 11:13:38 +08:00
...
}
}
2020-02-11 23:17:30 -08:00
Ray will then be able to utilize all cores of your machine. Find out how to configure the number of cores Ray will use at :ref: `configuring-ray` .
2020-06-26 09:29:22 -07:00
To start a multi-node Ray cluster, see the :ref: `cluster setup page <cluster-index>` .
2019-08-05 23:33:14 -07:00
2020-05-29 09:55:47 -07:00
.. _ray-remote-functions:
2019-08-05 23:33:14 -07:00
Remote functions (Tasks)
------------------------
2020-07-30 11:13:38 +08:00
Ray enables arbitrary functions to be executed asynchronously. These asynchronous Ray functions are called "remote functions". Here is an example.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. group-tab :: Python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code :: python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# A regular Python function.
def my_function():
return 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# By adding the `@ray.remote` decorator, a regular Python function
# becomes a Ray remote function.
@ray.remote
def my_function():
return 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# To invoke this remote function, use the `remote` method.
# This will immediately return an object ref (a future) and then create
# a task that will be executed on a worker process.
obj_ref = my_function.remote()
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# The result can be retrieved with `` ray.get `` .
assert ray.get(obj_ref) == 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
@ray.remote
def slow_function():
2021-02-10 15:31:47 -05:00
time.sleep(10)
return 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# Invocations of Ray remote functions happen in parallel.
# All computation is performed in the background, driven by Ray's internal event loop.
for _ in range(4):
# This doesn't block.
slow_function.remote()
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
See the `ray.remote package reference <package-ref.html> `__ page for specific documentation on how to use `` ray.remote `` .
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. group-tab :: Java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code :: java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
public class MyRayApp {
// A regular Java static method.
public static int myFunction() {
return 1;
}
}
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Invoke the above method as a Ray remote function.
// This will immediately return an object ref (a future) and then create
// a task that will be executed on a worker process.
ObjectRef<Integer> res = Ray.task(MyRayApp::myFunction).remote();
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// The result can be retrieved with `` ObjectRef::get `` .
Assert.assertTrue(res.get() == 1);
2019-08-05 23:33:14 -07:00
2020-07-31 15:35:43 +08:00
public class MyRayApp {
public static int slowFunction() throws InterruptedException {
TimeUnit.SECONDS.sleep(10);
return 1;
}
2020-07-30 11:13:38 +08:00
}
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Invocations of Ray remote functions happen in parallel.
// All computation is performed in the background, driven by Ray's internal event loop.
for(int i = 0; i < 4; i++) {
// This doesn't block.
Ray.task(MyRayApp::slowFunction).remote();
}
2020-03-04 13:35:46 -08:00
2020-07-30 11:13:38 +08:00
.. _ray-object-refs:
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
Passing object refs to remote functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2020-05-29 09:55:47 -07:00
2020-07-30 11:13:38 +08:00
**Object refs** can also be passed into remote functions. When the function actually gets executed, **the argument will be a retrieved as a regular object** . For example, take this function:
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
2019-08-05 23:33:14 -07:00
2019-08-28 17:54:15 -07:00
@ray.remote
2020-07-30 11:13:38 +08:00
def function_with_an_argument(value):
2019-08-28 17:54:15 -07:00
return value + 1
2020-07-30 11:13:38 +08:00
obj_ref1 = my_function.remote()
assert ray.get(obj_ref1) == 1
# You can pass an object ref as an argument to another Ray remote function.
obj_ref2 = function_with_an_argument.remote(obj_ref1)
assert ray.get(obj_ref2) == 2
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
2019-08-05 23:33:14 -07:00
2020-07-31 15:35:43 +08:00
public class MyRayApp {
public static int functionWithAnArgument(int value) {
return value + 1;
}
2020-07-30 11:13:38 +08:00
}
ObjectRef<Integer> objRef1 = Ray.task(MyRayApp::myFunction).remote();
Assert.assertTrue(objRef1.get() == 1);
// You can pass an object ref as an argument to another Ray remote function.
ObjectRef<Integer> objRef2 = Ray.task(MyRayApp::functionWithAnArgument, objRef1).remote();
Assert.assertTrue(objRef2.get() == 2);
2019-08-05 23:33:14 -07:00
Note the following behaviors:
- The second task will not be executed until the first task has finished
executing because the second task depends on the output of the first task.
- If the two tasks are scheduled on different machines, the output of the
2020-07-30 11:13:38 +08:00
first task (the value corresponding to `` obj_ref1/objRef1 `` ) will be sent over the
2019-08-05 23:33:14 -07:00
network to the machine where the second task is scheduled.
2020-09-21 11:27:50 -07:00
.. _resource-requirements:
2020-07-30 11:13:38 +08:00
Specifying required resources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-08-05 23:33:14 -07:00
Oftentimes, you may want to specify a task's resource requirements (for example
2020-07-30 11:13:38 +08:00
one task may require a GPU). Ray will automatically
2019-08-05 23:33:14 -07:00
detect the available GPUs and CPUs on the machine. However, you can override
2020-07-30 11:13:38 +08:00
this default behavior by passing in specific resources.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. group-tab :: Python
`` ray.init(num_cpus=8, num_gpus=4, resources={'Custom': 2}) ` ``
.. group-tab :: Java
Set Java system property: `` -Dray.resources=CPU:8,GPU:4,Custom:2 `` .
Ray also allows specifying a task's resources requirements (e.g., CPU, GPU, and custom resources).
The task will only run on a machine if there are enough resources
available to execute the task.
.. tabs ::
.. code-tab :: python
# Specify required resources.
@ray.remote(num_cpus=4, num_gpus=2)
def my_function():
return 1
.. code-tab :: java
// Specify required resources.
Ray.task(MyRayApp::myFunction).setResource("CPU", 1.0).setResource("GPU", 4.0).remote();
2019-08-05 23:33:14 -07:00
.. note ::
2020-07-30 11:13:38 +08:00
* If you do not specify any resources, the default is 1 CPU resource and
no other resources.
2019-08-05 23:33:14 -07:00
* If specifying CPUs, Ray does not enforce isolation (i.e., your task is
2019-09-07 11:50:18 -07:00
expected to honor its request).
2019-08-05 23:33:14 -07:00
* If specifying GPUs, Ray does provide isolation in forms of visible devices
(setting the environment variable `` CUDA_VISIBLE_DEVICES `` ), but it is the
task's responsibility to actually use the GPUs (e.g., through a deep
learning framework like TensorFlow or PyTorch).
The resource requirements of a task have implications for the Ray's scheduling
concurrency. In particular, the sum of the resource requirements of all of the
concurrently executing tasks on a given node cannot exceed the node's total
resources.
Below are more examples of resource specifications:
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
# Ray also supports fractional resource requirements.
@ray.remote(num_gpus=0.5)
def h():
return 1
# Ray support custom resources too.
@ray.remote(resources={'Custom': 1})
def f():
return 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Ray aslo supports fractional and custom resources.
Ray.task(MyRayApp::myFunction).setResource("GPU", 0.5).setResource("Custom", 1.0).remote();
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
Multiple returns
~~~~~~~~~~~~~~~~
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. group-tab :: Python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
Python remote functions can return multiple object refs.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-block :: python
2019-08-05 23:33:14 -07:00
2020-08-28 19:57:02 -07:00
@ray.remote(num_returns=3)
2020-07-30 11:13:38 +08:00
def return_multiple():
return 1, 2, 3
2020-05-20 10:31:57 -07:00
2020-07-30 11:13:38 +08:00
a, b, c = return_multiple.remote()
2020-05-20 10:31:57 -07:00
2020-07-30 11:13:38 +08:00
.. group-tab :: Java
2020-05-29 09:55:47 -07:00
2020-07-30 11:13:38 +08:00
Java remote functions doesn't support returning multiple objects.
Cancelling tasks
~~~~~~~~~~~~~~~~
.. tabs ::
.. group-tab :: Python
Remote functions can be canceled by calling `` ray.cancel `` (:ref: `docstring <ray-cancel-ref>` ) on the returned Object ref. Remote actor functions can be stopped by killing the actor using the `` ray.kill `` interface.
.. code-block :: python
@ray.remote
def blocking_operation():
time.sleep(10e6)
obj_ref = blocking_operation.remote()
ray.cancel(obj_ref)
2020-11-28 20:36:01 -08:00
from ray.exceptions import TaskCancelledError
2021-01-12 20:35:38 -08:00
try:
2020-11-28 20:36:01 -08:00
ray.get(obj_ref)
2021-01-12 20:35:38 -08:00
except TaskCancelledError:
2020-11-28 20:36:01 -08:00
print("Object reference was cancelled.")
2020-07-30 11:13:38 +08:00
.. group-tab :: Java
Task cancellation hasn't been implemented in Java yet.
2020-05-20 10:31:57 -07:00
2019-08-05 23:33:14 -07:00
Objects in Ray
--------------
2020-07-10 17:49:04 +08:00
In Ray, we can create and compute on objects. We refer to these objects as **remote objects** , and we use **object refs** to refer to them. Remote objects are stored in `shared-memory <https://en.wikipedia.org/wiki/Shared_memory> `__ **object stores** , and there is one object store per node in the cluster. In the cluster setting, we may not actually know which machine each object lives on.
2019-08-05 23:33:14 -07:00
2020-07-10 17:49:04 +08:00
An **object ref** is essentially a unique ID that can be used to refer to a
remote object. If you're familiar with futures, our object refs are conceptually
2019-08-05 23:33:14 -07:00
similar.
2020-07-10 17:49:04 +08:00
Object refs can be created in multiple ways.
2019-08-05 23:33:14 -07:00
1. They are returned by remote function calls.
2020-07-30 11:13:38 +08:00
2. They are returned by `` put `` (:ref: `docstring <ray-put-ref>` ).
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# Put an object in Ray's object store.
2019-08-28 17:54:15 -07:00
y = 1
2020-07-10 17:49:04 +08:00
object_ref = ray.put(y)
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
// Put an object in Ray's object store.
int y = 1;
ObjectRef<Integer> objectRef = Ray.put(y);
2020-05-13 22:52:38 -07:00
.. note ::
2019-08-05 23:33:14 -07:00
Remote objects are immutable. That is, their values cannot be changed after
creation. This allows remote objects to be replicated in multiple object
stores without needing to synchronize the copies.
Fetching Results
----------------
2020-07-30 11:13:38 +08:00
You can use the `` get `` method (:ref: `docstring <ray-get-ref>` ) to fetch the result of a remote object from an object ref.
If the current node's object store does not contain the object, the object is downloaded.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. group-tab :: Python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
If the object is a `numpy array <https://docs.scipy.org/doc/numpy/reference/generated/numpy.array.html> `__
or a collection of numpy arrays, the `` get `` call is zero-copy and returns arrays backed by shared object store memory.
Otherwise, we deserialize the object data into a Python object.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-block :: python
2019-11-14 00:50:04 -08:00
2020-07-30 11:13:38 +08:00
# Get the value of one object ref.
obj_ref = ray.put(1)
assert ray.get(obj_ref) == 1
2019-11-14 00:50:04 -08:00
2020-07-30 11:13:38 +08:00
# Get the values of multiple object refs in parallel.
assert ray.get([ray.put(i) for i in range(3)]) == [0, 1, 2]
2019-11-14 00:50:04 -08:00
2020-07-30 11:13:38 +08:00
# You can also set a timeout to return early from a `` get `` that's blocking for too long.
2020-08-28 19:57:02 -07:00
from ray.exceptions import GetTimeoutError
2020-07-30 11:13:38 +08:00
@ray.remote
2020-11-28 20:36:01 -08:00
def long_running_function():
2020-07-30 11:13:38 +08:00
time.sleep(8)
obj_ref = long_running_function.remote()
try:
ray.get(obj_ref, timeout=4)
2020-08-28 19:57:02 -07:00
except GetTimeoutError:
2020-07-30 11:13:38 +08:00
print("`get` timed out.")
.. group-tab :: Java
2019-11-14 00:50:04 -08:00
2020-07-30 11:13:38 +08:00
.. code-block :: java
2019-11-14 00:50:04 -08:00
2020-07-30 11:13:38 +08:00
// Get the value of one object ref.
ObjectRef<Integer> objRef = Ray.put(1);
Assert.assertTrue(object.get() == 1);
// Get the values of multiple object refs in parallel.
List<ObjectRef<Integer>> objRefs = new ArrayList<>();
for (int i = 0; i < 3; i++) {
objectRefs.add(Ray.put(i));
}
List<Integer> results = Ray.get(objectRefs);
Assert.assertEquals(results, ImmutableList.of(0, 1, 2));
2019-08-05 23:33:14 -07:00
After launching a number of tasks, you may want to know which ones have
2020-07-30 11:13:38 +08:00
finished executing. This can be done with `` wait `` (:ref: `ray-wait-ref` ). The function
2019-08-05 23:33:14 -07:00
works as follows.
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
ready_refs, remaining_refs = ray.wait(object_refs, num_returns=1, timeout=None)
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
WaitResult<Integer> waitResult = Ray.wait(objectRefs, /*num_returns=* /0, /*timeoutMs=* /1000);
System.out.println(waitResult.getReady()); // List of ready objects.
System.out.println(waitResult.getUnready()); // list of unready objects.
2019-08-05 23:33:14 -07:00
2021-02-02 00:07:47 -08:00
Object Spilling
2019-09-07 11:50:18 -07:00
---------------
2021-02-02 00:07:47 -08:00
When the object store gets full, objects will be `spilled to disk <memory-management.html#object-spilling> `__ .
This feature is available in Ray 1.3+.
2020-12-22 16:08:41 -08:00
2019-08-05 23:33:14 -07:00
Remote Classes (Actors)
-----------------------
2020-07-30 11:13:38 +08:00
Actors extend the Ray API from functions (tasks) to classes. An actor is essentially a stateful worker.
.. tabs ::
.. group-tab :: Python
The `` ray.remote `` decorator indicates that instances of the `` Counter `` class will be actors. Each actor runs in its own Python process.
.. code-block :: python
@ray.remote
class Counter(object):
def __init__(self):
self.value = 0
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
def increment(self):
self.value += 1
return self.value
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# Create an actor from this class.
counter = Counter.remote()
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. group-tab :: Java
2019-08-05 23:33:14 -07:00
2020-09-05 23:28:03 +08:00
`` Ray.actor `` is used to create actors from regular Java classes.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-block :: java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// A regular Java class.
public class Counter {
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
private int value = 0;
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
public int increment() {
this.value += 1;
return this.value;
}
}
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Create an actor from this class.
// `Ray.actor` takes a factory method that can produce
// a `Counter` object. Here, we pass `Counter` 's constructor
// as the argument.
ActorHandle<Counter> counter = Ray.actor(Counter::new).remote();
Specifying required resources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify resource requirements in actors too (see the `Actors section
2019-08-05 23:33:14 -07:00
<actors.html> `__ for more details.)
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# Specify required resources for an actor.
@ray.remote(num_cpus=2, num_gpus=0.5)
class Actor(object):
pass
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Specify required resources for an actor.
Ray.actor(Counter::new).setResource("CPU", 2.0).setResource("GPU", 0.5).remote();
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
Calling the actor
~~~~~~~~~~~~~~~~~
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
We can interact with the actor by calling its methods with the `` remote ``
operator. We can then call `` get `` on the object ref to retrieve the actual
value.
.. tabs ::
.. code-tab :: python
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
# Call the actor.
obj_ref = counter.increment.remote()
2020-11-28 20:36:01 -08:00
assert ray.get(obj_ref) == 1
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. code-tab :: java
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
// Call the actor.
ObjectRef<Integer> objectRef = counter.task(Counter::increment).remote();
Assert.assertTrue(objectRef.get() == 1);
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
Methods called on different actors can execute in parallel, and methods called on the same actor are executed serially in the order that they are called. Methods on the same actor will share state with one another, as shown below.
2019-08-05 23:33:14 -07:00
2020-07-30 11:13:38 +08:00
.. tabs ::
.. code-tab :: python
# Create ten Counter actors.
counters = [Counter.remote() for _ in range(10)]
# Increment each Counter once and get the results. These tasks all happen in
# parallel.
results = ray.get([c.increment.remote() for c in counters])
print(results) # prints [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
# Increment the first Counter five times. These tasks are executed serially
# and share state.
results = ray.get([counters[0].increment.remote() for _ in range(5)])
print(results) # prints [2, 3, 4, 5, 6]
.. code-tab :: java
// Create ten Counter actors.
List<ActorHandle<Counter>> counters = new ArrayList<>();
for (int i = 0; i < 10; i++) {
counters.add(Ray.actor(Counter::new).remote());
}
// Increment each Counter once and get the results. These tasks all happen in
// parallel.
List<ObjectRef<Integer>> objectRefs = new ArrayList<>();
for (ActorHandle<Counter> counterActor : counters) {
objectRefs.add(counterActor.task(Counter::increment).remote());
}
// prints [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
System.out.println(Ray.get(objectRefs));
// Increment the first Counter five times. These tasks are executed serially
// and share state.
objectRefs = new ArrayList<>();
for (int i = 0; i < 5; i++) {
objectRefs.add(counters.get(0).task(Counter::increment).remote());
}
// prints [2, 3, 4, 5, 6]
System.out.println(Ray.get(objectRefs));
2019-08-05 23:33:14 -07:00
To learn more about Ray Actors, see the `Actors section <actors.html> `__ .