add java tutorial (#2491)

This commit is contained in:
Hao Chen
2018-07-29 08:09:30 +08:00
committed by Robert Nishihara
parent 90a3ea9443
commit 0ea7a6abf0
18 changed files with 811 additions and 385 deletions
+5 -315
View File
@@ -2,7 +2,6 @@ This directory contains the java worker, with the following components.
- java/api: Ray API definition
- java/common: utilities
- java/hook: binary rewrite of the Java byte-code for remote execution
- java/runtime-common: common implementation of the runtime in worker
- java/runtime-dev: a pure-java mock implementation of the runtime for
fast development
@@ -11,21 +10,6 @@ This directory contains the java worker, with the following components.
- src/local\_scheduler/lib/java: JNI client library for local scheduler
- src/plasma/lib/java: JNI client library for plasma storage
Build and test
==============
::
# build native components
../build.sh -l java
# build java worker
mvn clean install -Dmaven.test.skip
# test
export RAY_CONFIG=ray.config.ini
mvn test
Quick start
===========
@@ -92,304 +76,10 @@ correspondent calls executed on remote machines.
}
}
Ray Java API
============
More information
================
Basic API
---------
- `Installation <https://github.com/ray-project/ray/tree/master/java/doc/installation.rst>`_
- `API document <https://github.com/ray-project/ray/tree/master/java/doc/api.rst>`_
- `Tutorial <https://github.com/ray-project/ray/tree/master/java/tutorial>`_
``Ray.init()``
~~~~~~~~~~~~~~
Ray.init should be invoked before any other Ray functions to initialize
the runtime.
``@RayRemote``
~~~~~~~~~~~~~~
The annotation of ``@RayRemote`` can be used to decorate static java
method or class. The former indicates that a target function is a remote
function, which is valid with the follow requirements. \* it must be a
public static method \* parameters and return value must not be the
primitive type of java such as int, double, but could use the wrapper
class like Integer,Double \* the return value of the method must always
be the same with the same input
When the annotation is used for classes, the classes are considered
actors(a mechanism to share state among many remote functions). The
member functions can be invoked using ``Ray.call``. The requirements for
an actor class are as follows. \* it must have an constructor without
any parameter \* if it is an inner class, it must be public static \* it
must not have a member field or method decorated using
``public static``, as the semantic is undefined with multiple instances
of this same class on different machines \* an actor method must be
decorated using ``public`` but no ``static``, and the other requirements
are the same as above.
``Ray.call``
~~~~~~~~~~~~
.. code:: java
RayObject<R> call(Func func, ...);
``func`` is the target method, continued with appropriate parameters.
There are some requirements here:
- the return type of ``func`` must be ``R``
- currently at most 6 parameters of ``func`` are allowed
- each parameter must be of type ``T`` of the correspondent ``func``'s
parameter, or be the lifted ``RayObject<T>`` to indicate a result
from another ray call
The returned object is labled as ``RayObject<R>`` and its value will be
put into memory of the machine where the function call is executed.
``Ray.put``
~~~~~~~~~~~
You can also invoke ``Ray.put`` to explicitly place an object into local
memory.
.. code:: java
public static <T> RayObject<T> put(T object);
public static <T, TM> RayObject<T> put(T obj, TM metadata);
``RayObject<T>.get/getMeta``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: java
public class RayObject<T> {
public T get() throws TaskExecutionException;
public <M> M getMeta() throws TaskExecutionException;
}
This method blocks current thread until requested data gets ready and is
fetched (if needed) from remote memory to local.
``Ray.wait``
~~~~~~~~~~~~
Calling ``Ray.wait`` will block current thread and wait for specified
ray calls. It returns when at least ``numReturns`` calls are completed,
or the ``timeout`` expires. See multi-value support for ``RayList``.
.. code:: java
public static WaitResult<T> wait(RayList<T> waitfor, int numReturns, int timeout);
public static WaitResult<T> wait(RayList<T> waitfor, int numReturns);
public static WaitResult<T> wait(RayList<T> waitfor);
Multi-value API
---------------
Multi-value Types
~~~~~~~~~~~~~~~~~
Java worker supports multiple ``RayObject``\ s in a single data
structure as a return value or a ray call parameter, through the
following container types.
``MultipleReturnsX<R0, R1, ...>``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
There are multiple heterogeneous values, with their types as ``R0``,
``R1``,... respectively. Note currently this container type is only
supported as the return type of a ray call, therefore you can not use it
as the type of an input parameter.
``RayList<T>``
''''''''''''''
A list of ``RayObject<T>``, inherited from ``List<T>`` in Java. It can
be used as the type for both return value and parameters.
``RayMap<L, T>``
''''''''''''''''
A map of ``RayObject<T>`` with each indexed using a label with type
``L``, inherited from ``Map<L, T>``. It can be used as the type for both
return value and parameters.
Enable multiple heterogeneous return values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Java worker support at most four multiple heterogeneous return values,
and in order to let the runtime know the number of return values we
supply the method of ``Ray.call_X`` as follows.
.. code:: java
RayObjects2<R0, R1> call_2(Func func, ...);
RayObjects3<R0, R1, R2> call_3(Func func, ...);
RayObjects4<R0, R1, R2, R3> call_4(Func func, ...);
Note ``func`` must match the following requirements.
- It must hava the return value of ``MultipleReturnsX``, and must be
invoked using correspondent ``Ray.call_X``
Here is an example.
.. code:: java
public class MultiRExample {
public static void main(String[] args) {
Ray.init();
RayObjects2<Integer, String> refs = Ray.call_2(MultiRExample::sayMultiRet);
Integer obj1 = refs.r0().get();
String obj2 = refs.r1().get();
Assert.assertTrue(obj1.equals(123));
Assert.assertTrue(obj2.equals("123"));
}
@RayRemote
public static MultipleReturns2<Integer, String> sayMultiRet() {
return new MultipleReturns2<Integer, String>(123, "123");
}
}
Return with ``RayList``
~~~~~~~~~~~~~~~~~~~~~~~
We use ``Ray.call_n`` to do so, which is similar to ``Ray.call`` except
an additional parameter ``returnCount`` which tells the number of return
``RayObject<R>`` in ``RayList<R>``. This is because Ray core engines
needs to know it before the method is really called.
.. code:: java
RayList<R> call_n(Func func, Integer returnCount, ...);
Here is an example.
.. code:: java
public class ListRExample {
public static void main(String[] args) {
Ray.init();
RayList<Integer> ns = Ray.call_n(ListRExample::sayList, 10, 10);
for (int i = 0; i < 10; i++) {
RayObject<Integer> obj = ns.Get(i);
Assert.assertTrue(i == obj.get());
}
}
@RayRemote
public static List<Integer> sayList(Integer count) {
ArrayList<Integer> rets = new ArrayList<>();
for (int i = 0; i < count; i++)
rets.add(i);
return rets;
}
}
Return with ``RayMap``
~~~~~~~~~~~~~~~~~~~~~~
This is similar to ``RayList`` case, except that now each return
``RayObject<R>`` in ``RayMap<L,R>`` has a given label when
``Ray.call_n`` is made.
.. code:: java
RayMap<L, R> call_n(Func func, Collection<L> returnLabels, ...);
Here is an example.
.. code:: java
public class MapRExample {
public static void main(String[] args) {
Ray.init();
RayMap<Integer, String> ns = Ray.call_n(MapRExample::sayMap,
Arrays.asList(1, 2, 4, 3), "n_futures_");
for (Entry<Integer, RayObject<String>> ne : ns.EntrySet()) {
Integer key = ne.getKey();
RayObject<String> obj = ne.getValue();
Assert.assertTrue(obj.get().equals("n_futures_" + key));
}
}
@RayRemote(externalIO = true)
public static Map<Integer, String> sayMap(Collection<Integer> ids,
String prefix) {
Map<Integer, String> ret = new HashMap<>();
for (int id : ids) {
ret.put(id, prefix + id);
}
return ret;
}
}
Enable ``RayList`` and ``RayMap`` as parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: java
public class ListTExample {
public static void main(String[] args) {
Ray.init();
RayList<Integer> ints = new RayList<>();
ints.add(Ray.put(new Integer(1)));
ints.add(Ray.put(new Integer(1)));
ints.add(Ray.put(new Integer(1)));
RayObject<Integer> obj = Ray.call(ListTExample::sayReadRayList
(List<Integer>)ints);
Assert.assertTrue(obj.get().equals(3));
}
@RayRemote
public static int sayReadRayList(List<Integer> ints) {
int sum = 0;
for (Integer i : ints) {
sum += i;
}
return sum;
}
}
Actor Support
-------------
Create Actors
~~~~~~~~~~~~~
A regular class annotated with ``@RayRemote`` is an actor class.
.. code:: java
@RayRemote
public class Adder {
public Adder() {
sum = 0;
}
public Integer add(Integer n) {
return sum += n;
}
private Integer sum;
}
Whenever you call ``Ray.create()`` method, an actor will be created, and
you get a local ``RayActor`` of that actor as the return value.
.. code:: java
RayActor<Adder> adder = Ray.create(Adder.class);
Call Actor Methods
~~~~~~~~~~~~~~~~~~
The same ``Ray.call`` or its extended versions (e.g., ``Ray.call_n``) is
applied, except that the first argument becomes ``RayActor``.
.. code:: java
RayObject<R> Ray.call(Func func, RayActor<Adder> actor, ...);
RayObject<Integer> result1 = Ray.call(Adder::add, adder, 1);
RayObject<Integer> result2 = Ray.call(Adder::add, adder, 10);
result2.get(); // 11
+306
View File
@@ -0,0 +1,306 @@
Ray Java API
============
Basic API
---------
``Ray.init()``
~~~~~~~~~~~~~~
Ray.init should be invoked before any other Ray functions to initialize
the runtime.
``@RayRemote``
~~~~~~~~~~~~~~
The ``@RayRemote`` annotation can be used to decorate static java
methods and classes. The former indicates that a target function is a remote
function, which is valid with the follow requirements.
- It must be a public static method.
- Its parameters and return value cannot be primitive types like int or
double but can use wrapper classes like Integer or Double.
- The method must be deterministic for task reconstruction to behave correctly.
When the annotation is used for a class, the class becomes an actor class
(an encapsulation of state shared among many remote functions). The
member functions can be invoked using ``Ray.call``. The requirements for
an actor class are as follows.
- It must have a constructor without any parameters.
- Any inner class must be public static.
- It must not have a member field or method decorated using ``public static``,
as the semantic is undefined with multiple instances of this same class on
different machines
- An actor method must be decorated using ``public`` but not ``static``
- The other requirements are the same as for remote functions.
``Ray.call``
~~~~~~~~~~~~
Here is a simple example of invoking a remote function using ``Ray.call``.
.. code:: java
RayObject<R> call(Func func, ...);
Here, ``func`` is the target method and the ``...``'s should be filled in with
the arguments to ``func``. In addition, the following must hold.
- The return type of ``func`` must be ``R``.
- Currently at most 6 parameters of ``func`` are allowed.
- Each parameter must have the same type ``T`` as the corresponding parameter
to ``func``, or it must have the type ``RayObject<T>`` to indicate a result
from another ``Ray.call`` invocation.
The returned object is labeled as ``RayObject<R>`` and its value will be
put into the object store on the machine where the function call is executed.
``Ray.put``
~~~~~~~~~~~
You can also invoke ``Ray.put`` to explicitly place an object into the object
store.
.. code:: java
public static <T> RayObject<T> put(T object);
public static <T, TM> RayObject<T> put(T obj, TM metadata);
``RayObject<T>.get/getMeta``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: java
public class RayObject<T> {
public T get() throws TaskExecutionException;
public <M> M getMeta() throws TaskExecutionException;
}
This method blocks the current thread until the requested data is ready and has
been fetched (if necessary) from a remote machine.
``Ray.wait``
~~~~~~~~~~~~
Calling ``Ray.wait`` will block the current thread and wait for specified
ray calls. It returns when at least ``numReturns`` calls are completed,
or the ``timeout`` expires. See multi-value support for ``RayList``.
.. code:: java
public static WaitResult<T> wait(RayList<T> waitfor, int numReturns, int timeout);
public static WaitResult<T> wait(RayList<T> waitfor, int numReturns);
public static WaitResult<T> wait(RayList<T> waitfor);
Multi-value API
---------------
Multi-value Types
~~~~~~~~~~~~~~~~~
Multiple ``RayObject``'s can be placed in a single data
structure as a return value or as a ``Ray.call`` parameter through the
following container types.
``MultipleReturnsX<R0, R1, ...>``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This consists of multiple heterogeneous values, with types ``R0``,
``R1``,... respectively. Currently this container type is only
supported as the return type of ``Ray.call``. Therefore you cannot use it
as the type of an input parameter.
``RayList<T>``
^^^^^^^^^^^^^^
This is a list of ``RayObject<T>``s, which inherits from ``List<T>`` in Java. It
can be used as the type for both a return value and a parameter value.
``RayMap<L, T>``
^^^^^^^^^^^^^^^^
A map of ``RayObject<T>``s with each indexed using a label with type
``L``, inherited from ``Map<L, T>``. It can be used as the type for both
a return value and a parameter value.
Enable multiple heterogeneous return values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
At most four multiple heterogeneous return values are supported.
In order to let the runtime know the number of return values, we
supply the method of ``Ray.call_X`` as follows.
.. code:: java
RayObjects2<R0, R1> call_2(Func func, ...);
RayObjects3<R0, R1, R2> call_3(Func func, ...);
RayObjects4<R0, R1, R2, R3> call_4(Func func, ...);
Note ``func`` must match the following requirements.
- It must have a return value of type ``MultipleReturnsX``, and must be
invoked using the corresponding ``Ray.call_X``.
Here is an example.
.. code:: java
public class MultiRExample {
public static void main(String[] args) {
Ray.init();
RayObjects2<Integer, String> refs = Ray.call_2(MultiRExample::sayMultiRet);
Integer obj1 = refs.r0().get();
String obj2 = refs.r1().get();
Assert.assertTrue(obj1.equals(123));
Assert.assertTrue(obj2.equals("123"));
}
@RayRemote
public static MultipleReturns2<Integer, String> sayMultiRet() {
return new MultipleReturns2<Integer, String>(123, "123");
}
}
Return with ``RayList``
~~~~~~~~~~~~~~~~~~~~~~~
We use ``Ray.call_n`` to do so, which is similar to ``Ray.call`` except it has
an additional parameter ``returnCount`` which specifies the number of return
``RayObject<R>``s in ``RayList<R>``. This is because Ray needs to know the
number of return values before the method is actually executed.
.. code:: java
RayList<R> call_n(Func func, Integer returnCount, ...);
Here is an example.
.. code:: java
public class ListRExample {
public static void main(String[] args) {
Ray.init();
RayList<Integer> ns = Ray.call_n(ListRExample::sayList, 10, 10);
for (int i = 0; i < 10; i++) {
RayObject<Integer> obj = ns.Get(i);
Assert.assertTrue(i == obj.get());
}
}
@RayRemote
public static List<Integer> sayList(Integer count) {
ArrayList<Integer> rets = new ArrayList<>();
for (int i = 0; i < count; i++)
rets.add(i);
return rets;
}
}
Return with ``RayMap``
~~~~~~~~~~~~~~~~~~~~~~
This is similar to ``RayList`` case, except that now each return
``RayObject<R>`` in ``RayMap<L,R>`` has a given label when
``Ray.call_n`` is made.
.. code:: java
RayMap<L, R> call_n(Func func, Collection<L> returnLabels, ...);
Here is an example.
.. code:: java
public class MapRExample {
public static void main(String[] args) {
Ray.init();
RayMap<Integer, String> ns = Ray.call_n(MapRExample::sayMap,
Arrays.asList(1, 2, 4, 3), "n_futures_");
for (Entry<Integer, RayObject<String>> ne : ns.EntrySet()) {
Integer key = ne.getKey();
RayObject<String> obj = ne.getValue();
Assert.assertTrue(obj.get().equals("n_futures_" + key));
}
}
@RayRemote(externalIO = true)
public static Map<Integer, String> sayMap(Collection<Integer> ids,
String prefix) {
Map<Integer, String> ret = new HashMap<>();
for (int id : ids) {
ret.put(id, prefix + id);
}
return ret;
}
}
Enable ``RayList`` and ``RayMap`` as parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: java
public class ListTExample {
public static void main(String[] args) {
Ray.init();
RayList<Integer> ints = new RayList<>();
ints.add(Ray.put(new Integer(1)));
ints.add(Ray.put(new Integer(1)));
ints.add(Ray.put(new Integer(1)));
RayObject<Integer> obj = Ray.call(ListTExample::sayReadRayList
(List<Integer>)ints);
Assert.assertTrue(obj.get().equals(3));
}
@RayRemote
public static int sayReadRayList(List<Integer> ints) {
int sum = 0;
for (Integer i : ints) {
sum += i;
}
return sum;
}
}
Actor Support
-------------
Create Actors
~~~~~~~~~~~~~
A regular class annotated with ``@RayRemote`` is an actor class.
.. code:: java
@RayRemote
public class Adder {
public Adder() {
sum = 0;
}
public Integer add(Integer n) {
return sum += n;
}
private Integer sum;
}
Whenever you call ``Ray.create()`` method, an actor will be created, and
you get a local ``RayActor`` of that actor as the return value.
.. code:: java
RayActor<Adder> adder = Ray.create(Adder.class);
Call Actor Methods
~~~~~~~~~~~~~~~~~~
The same ``Ray.call`` or its extended versions (e.g., ``Ray.call_n``) is
applied, except that the first argument becomes ``RayActor``.
.. code:: java
RayObject<R> Ray.call(Func func, RayActor<Adder> actor, ...);
RayObject<Integer> result1 = Ray.call(Adder::add, adder, 1);
RayObject<Integer> result2 = Ray.call(Adder::add, adder, 10);
result2.get(); // 11
+61
View File
@@ -0,0 +1,61 @@
Install Ray for Java
====================
Ray works for Java 8 and above. Currently, we only support building Ray from source.
Build from source
-----------------
Install dependencies
^^^^^^^^^^^^^^^^^^^^
First, make sure JDK 8 or above is installed on your machine. If not, you can download it from `here <http://www.oracle.com/technetwork/java/javase/downloads/index.html>`_.
Then install the following dependencies.
For Ubuntu users, run the following commands:
::
sudo apt-get update
sudo apt-get install -y maven cmake pkg-config build-essential autoconf curl libtool unzip flex bison python # we install python here because python2 is required to build the webui
# If you are not using Anaconda, you need the following.
sudo apt-get install python-dev # For Python 2.
sudo apt-get install python3-dev # For Python 3.
# If you are on Ubuntu 14.04, you need the following.
pip install cmake
pip install cython
For macOS users, run the following commands:
::
brew update
brew install maven cmake pkg-config automake autoconf libtool openssl bison wget
pip install cython
Build Ray
^^^^^^^^^
Then we can start building Ray with the following commands:
::
git clone https://github.com/ray-project/ray.git
cd ray
# build native components
./build.sh -l java
# build java API
cd java
mvn clean install -Dmaven.test.skip
Run tests
^^^^^^^^^
::
# in `ray/java` directory
export RAY_CONFIG=ray.config.ini
mvn test
-5
View File
@@ -1,5 +0,0 @@
#!/usr/bin/env bash
#first you should run the ../test.sh to build
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd)
export RAY_CONFIG=$ROOT_DIR/../ray.config.ini
java -Djava.library.path=../../build/src/plasma:../../build/src/local_scheduler -cp .:target/ray-example-1.0.jar:lib/* org.ray.example.HelloWorld
@@ -1,57 +0,0 @@
package org.ray.example;
import java.io.Serializable;
import org.ray.api.Ray;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
import org.ray.util.logger.RayLog;
public class HelloWorld implements Serializable {
@RayRemote
public static String sayHello() {
String ret = "he";
ret += "llo";
RayLog.rapp.info("real say hello");
return ret;
}
@RayRemote
public static String sayWorld() {
String ret = "world";
ret += "!";
return ret;
}
@RayRemote
public static String merge(String hello, String world) {
return hello + "," + world;
}
public static void main(String[] args) throws Exception {
try {
Ray.init();
RayLog.rapp.info("HelloWorld.main() has " + args.length + " args");
for (String arg: args) {
RayLog.rapp.info("arg: " + arg);
}
String helloWorld = HelloWorld.sayHelloWorld();
RayLog.rapp.info(helloWorld);
assert helloWorld.equals("hello,world!");
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
public static String sayHelloWorld() {
RayObject<String> hello = Ray.call(HelloWorld::sayHello);
RayObject<String> world = Ray.call(HelloWorld::sayWorld);
return Ray.call(HelloWorld::merge, hello, world).get();
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
<module>runtime-dev</module>
<module>cli</module>
<module>test</module>
<module>example</module>
<module>tutorial</module>
</modules>
<properties>
+2 -2
View File
@@ -87,7 +87,7 @@ driver_args =
%CONFIG_FILE_DIR%/runtime-native/target/classes =
%CONFIG_FILE_DIR%/runtime-native/target/test-classes =
%CONFIG_FILE_DIR%/example/target/classes =
%CONFIG_FILE_DIR%/tutorial/target/classes =
%CONFIG_FILE_DIR%/test/target/classes =
%CONFIG_FILE_DIR%/test/target/test-classes =
@@ -104,7 +104,7 @@ driver_args =
%CONFIG_FILE_DIR%/test/target/test-classes =
%CONFIG_FILE_DIR%/test/lib/* =
%CONFIG_FILE_DIR%/example/target/ray-example-1.0.jar =
%CONFIG_FILE_DIR%/tutorial/target/ray-tutorial-1.0.jar =
[ray.java.path.classes.deploy]
%CONFIG_FILE_DIR%/java/lib/* =
+1 -1
View File
@@ -19,7 +19,7 @@ pushd example
if [ ! -d "app1/" ];then
mkdir app1
fi
cp -rf target/ray-example-1.0.jar app1/
cp -rf target/ray-tutorial-1.0.jar app1/
zip -r app1.zip app1
popd
+31
View File
@@ -0,0 +1,31 @@
Ray Java Tutorial
=================
- `Installation guide <https://github.com/ray-project/ray/tree/master/java/doc/installation.rst>`_
- `API document <https://github.com/ray-project/ray/tree/master/java/doc/api.rst>`_
Exercises
---------
Each file ``java/example/src/main/java/org/ray/exercise/Exercise*.java`` is a separate exercise.
To run a exercise case, set the ``RAY_CONFIG`` env variable and run the following command in ``ray/java/`` directory.
.. code-block:: shell
java -Djava.library.path=../build/src/plasma/:../build/src/local_scheduler/ -classpath "tutorial/target/ray-tutorial-1.0.jar:tutorial/lib/*" org.ray.exercise.Exercise01
`Exercise 1 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise01.java>`_: Define a remote function, and execute multiple remote functions in parallel.
`Exercise 2 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise02.java>`_: Execute remote functions in parallel with some dependencies.
`Exercise 3 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise03.java>`_: Call remote functions from within remote functions.
`Exercise 4 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise04.java>`_: Use ``Ray.wait`` to ignore stragglers.
`Exercise 5 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise05.java>`_: Use multiple heterogeneous return values.
`Exercise 6 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise06.java>`_: Usage of ``RayList<T>``.
`Exercise 7 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise07.java>`_: Usage of ``RayMap<L, T>``.
`Exercise 8 <https://github.com/ray-project/ray/tree/master/java/tutorial/src/main/java/org/ray/exercise/Exercise08.java>`_: Actor Support of create Actor and call Actor method.
@@ -11,10 +11,10 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.ray</groupId>
<artifactId>ray-example</artifactId>
<artifactId>ray-tutorial</artifactId>
<name>java example for ray</name>
<description>java example for ray</description>
<name>java tutorial</name>
<description>Tutorial of using Ray with Java</description>
<url></url>
<packaging>jar</packaging>
@@ -94,4 +94,4 @@
</plugins>
</build>
</project>
</project>
@@ -0,0 +1,47 @@
package org.ray.exercise;
import java.io.Serializable;
import org.ray.api.Ray;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Define a remote function, and execute multiple remote functions in parallel.
*/
public class Exercise01 implements Serializable {
/**
* A plain remote function.
*/
// `@RayRemote` annotation converts a normal function to a remote function.
@RayRemote
public static String sayHello() {
String ret = "hello";
System.out.println(ret);
return ret;
}
@RayRemote
public static String sayWorld() {
String ret = "world!";
System.out.println(ret);
return ret;
}
public static void main(String[] args) throws Exception {
try {
// Use `Ray.init` to initialize the Ray runtime.
Ray.init();
// Use `Ray.call` to call a remote function.
RayObject<String> hello = Ray.call(Exercise01::sayHello);
RayObject<String> world = Ray.call(Exercise01::sayWorld);
System.out.println("First remote call result:" + hello.get());
System.out.println("Second remote call result:" + world.get());
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
}
@@ -0,0 +1,54 @@
package org.ray.exercise;
import org.ray.api.Ray;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Execute remote functions in parallel with some dependencies.
*/
public class Exercise02 {
@RayRemote
public static String sayHello() {
String ret = "hello";
System.out.println(ret);
return ret;
}
@RayRemote
public static String sayWorld() {
String ret = "world!";
System.out.println(ret);
return ret;
}
/**
* A remote function with dependency.
*/
@RayRemote
public static String merge(String hello, String world) {
return hello + "," + world;
}
public static String sayHelloWorld() {
RayObject<String> hello = Ray.call(Exercise02::sayHello);
RayObject<String> world = Ray.call(Exercise02::sayWorld);
// Pass unfinished results as the parameters to another remote function.
return Ray.call(Exercise02::merge, hello, world).get();
}
public static void main(String[] args) throws Exception {
try {
Ray.init();
String helloWorld = Exercise02.sayHelloWorld();
System.out.println(helloWorld);
assert helloWorld.equals("hello,world!");
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
}
@@ -0,0 +1,45 @@
package org.ray.exercise;
import org.ray.api.Ray;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Call a remote function from within another remote function.
*/
public class Exercise03 {
/**
* A remote function which will call another remote function.
*/
@RayRemote
public static String sayHelloWithWorld() {
String ret = "hello";
System.out.println(ret);
RayObject<String> world = Ray.call(Exercise03::sayWorld);
return ret + "," + world.get();
}
/**
* A remote function which will be called by another remote function.
*/
@RayRemote
public static String sayWorld() {
String ret = "world!";
System.out.println(ret);
return ret;
}
public static void main(String[] args) throws Exception {
try {
Ray.init();
String helloWithWorld = Ray.call(Exercise03::sayHelloWithWorld).get();
System.out.println(helloWithWorld);
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
}
@@ -0,0 +1,74 @@
package org.ray.exercise;
import org.ray.api.Ray;
import org.ray.api.RayList;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.api.WaitResult;
import org.ray.core.RayRuntime;
/**
* Use Ray.wait to ignore stragglers
*/
public class Exercise04 {
@RayRemote
public static String f1() {
String ret = "f1";
System.out.println(ret);
return ret;
}
@RayRemote
public static String f2() {
String ret = "f2";
System.out.println(ret);
return ret;
}
/**
* A slow remote function.
*/
@RayRemote
public static String f3() {
String ret = "f3";
try {
Thread.sleep(5000L);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(ret);
return ret;
}
public static void main(String[] args) throws Exception {
try {
Ray.init();
RayObject<String> o1 = Ray.call(Exercise04::f1);
RayObject<String> o2 = Ray.call(Exercise04::f2);
RayObject<String> o3 = Ray.call(Exercise04::f3);
RayList<String> rayList = new RayList<>();
rayList.add(o1);
rayList.add(o2);
rayList.add(o3);
// Ray.wait will block until specified number of results are ready
// or specified timeout have passed.
// In this case, the result of f3 will be ignored.
WaitResult<String> waitResult = Ray.wait(rayList, 2, 3000);
RayList<String> readyOnes = waitResult.getReadyOnes();
RayList<String> remainOnes = waitResult.getRemainOnes();
System.out.println("Number of readyOnes: " + readyOnes.size());
for (int i = 0; i < readyOnes.size(); i++) {
System.out.println("The value of readyOnes " + i + " is " + readyOnes.get(i));
}
System.out.println("Number of remainOnes: " + remainOnes.size());
for (int i = 0; i < remainOnes.size(); i++) {
System.out.println("The value of remainOnes " + i + " is " + remainOnes.get(i));
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
}
@@ -0,0 +1,38 @@
package org.ray.exercise;
import org.ray.api.Ray;
import org.ray.api.RayRemote;
import org.ray.api.returns.MultipleReturns2;
import org.ray.api.returns.RayObjects2;
import org.ray.core.RayRuntime;
/**
* Use multiple heterogeneous return values
* Java worker support at most four heterogeneous return values,
* To call such remote functions, use {@code Ray.call_X} as follows.
*/
public class Exercise05 {
public static void main(String[] args) {
try {
Ray.init();
RayObjects2<Integer, String> refs = Ray.call_2(Exercise05::sayMultiRet);
Integer obj1 = refs.r0().get();
String obj2 = refs.r1().get();
System.out.println(obj1);
System.out.println(obj2);
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
/**
* A remote function that returns multiple heterogeneous values.
*/
@RayRemote
public static MultipleReturns2<Integer, String> sayMultiRet() {
return new MultipleReturns2<Integer, String>(123, "123");
}
}
@@ -0,0 +1,46 @@
package org.ray.exercise;
import java.util.ArrayList;
import java.util.List;
import org.ray.api.Ray;
import org.ray.api.RayList;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Show usage of RayList.
* RayList is a list of {@code RayObject}s, inherited from {@code List}.
* It can be used as the type for both return values and parameters.
*
*/
public class Exercise06 {
public static void main(String[] args) {
try {
Ray.init();
// The result is a `RayList`.
RayList<Integer> ns = Ray.call_n(Exercise06::sayList, 10, 10);
for (int i = 0; i < 10; i++) {
RayObject<Integer> obj = ns.Get(i);
System.out.println(obj.get());
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
/**
* A remote function that returns a list.
*/
@RayRemote
public static List<Integer> sayList(Integer count) {
ArrayList<Integer> rets = new ArrayList<>();
for (int i = 0; i < count; i++) {
rets.add(i);
}
return rets;
}
}
@@ -0,0 +1,48 @@
package org.ray.exercise;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.ray.api.Ray;
import org.ray.api.RayMap;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Show usage of RayMap.
* {@code RayMap} is a map of {@code RayObject}s, inherited from {@code Map}.
* It can be used as the type for both return values and parameters.
*/
public class Exercise07 {
public static void main(String[] args) {
try {
Ray.init();
RayMap<Integer, String> ns = Ray.call_n(Exercise07::sayMap,
Arrays.asList(1, 2, 4, 3), "n_futures_");
for (Map.Entry<Integer, RayObject<String>> ne : ns.EntrySet()) {
Integer key = ne.getKey();
RayObject<String> obj = ne.getValue();
System.out.println(obj.get());
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
/**
* A remote function that returns a map.
*/
@RayRemote()
public static Map<Integer, String> sayMap(Collection<Integer> ids, String prefix) {
Map<Integer, String> ret = new HashMap<>();
for (int id : ids) {
ret.put(id, prefix + id);
}
return ret;
}
}
@@ -0,0 +1,48 @@
package org.ray.exercise;
import org.ray.api.Ray;
import org.ray.api.RayActor;
import org.ray.api.RayObject;
import org.ray.api.RayRemote;
import org.ray.core.RayRuntime;
/**
* Show usage of actors.
*/
public class Exercise08 {
public static void main(String[] args) {
try {
Ray.init();
// `Ray.create` creates an actor instance.
RayActor<Adder> adder = Ray.create(Adder.class);
// Use `Ray.call(actor, parameters)` to call an actor method.
RayObject<Integer> result1 = Ray.call(Adder::add, adder, 1);
RayObject<Integer> result2 = Ray.call(Adder::add, adder, 10);
System.out.println(result1.get());
System.out.println(result2.get());
} catch (Throwable t) {
t.printStackTrace();
} finally {
RayRuntime.getInstance().cleanUp();
}
}
/**
* An example actor.
*/
// `@RayRemote` annotation also converts a normal class to an actor.
@RayRemote
public static class Adder {
public Adder() {
sum = 0;
}
public Integer add(Integer n) {
return sum += n;
}
private Integer sum;
}
}