diff --git a/java/README.rst b/java/README.rst index d9205bd14..5d6e0ab4c 100644 --- a/java/README.rst +++ b/java/README.rst @@ -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 `_ +- `API document `_ +- `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 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`` to indicate a result - from another ray call - -The returned object is labled as ``RayObject`` 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 RayObject put(T object); - public static RayObject put(T obj, TM metadata); - -``RayObject.get/getMeta`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: java - - public class RayObject { - public T get() throws TaskExecutionException; - public 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 wait(RayList waitfor, int numReturns, int timeout); - public static WaitResult wait(RayList waitfor, int numReturns); - public static WaitResult wait(RayList 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`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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`` -'''''''''''''' - -A list of ``RayObject``, inherited from ``List`` in Java. It can -be used as the type for both return value and parameters. - -``RayMap`` -'''''''''''''''' - -A map of ``RayObject`` with each indexed using a label with type -``L``, inherited from ``Map``. 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 call_2(Func func, ...); - RayObjects3 call_3(Func func, ...); - RayObjects4 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 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 sayMultiRet() { - return new MultipleReturns2(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`` in ``RayList``. This is because Ray core engines -needs to know it before the method is really called. - -.. code:: java - - RayList call_n(Func func, Integer returnCount, ...); - -Here is an example. - -.. code:: java - - public class ListRExample { - public static void main(String[] args) { - Ray.init(); - RayList ns = Ray.call_n(ListRExample::sayList, 10, 10); - for (int i = 0; i < 10; i++) { - RayObject obj = ns.Get(i); - Assert.assertTrue(i == obj.get()); - } - } - - @RayRemote - public static List sayList(Integer count) { - ArrayList 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`` in ``RayMap`` has a given label when -``Ray.call_n`` is made. - -.. code:: java - - RayMap call_n(Func func, Collection returnLabels, ...); - -Here is an example. - -.. code:: java - - public class MapRExample { - public static void main(String[] args) { - Ray.init(); - RayMap ns = Ray.call_n(MapRExample::sayMap, - Arrays.asList(1, 2, 4, 3), "n_futures_"); - for (Entry> ne : ns.EntrySet()) { - Integer key = ne.getKey(); - RayObject obj = ne.getValue(); - Assert.assertTrue(obj.get().equals("n_futures_" + key)); - } - } - - @RayRemote(externalIO = true) - public static Map sayMap(Collection ids, - String prefix) { - Map 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 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 obj = Ray.call(ListTExample::sayReadRayList, - (List)ints); - Assert.assertTrue(obj.get().equals(3)); - } - - @RayRemote - public static int sayReadRayList(List 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 = 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 Ray.call(Func func, RayActor actor, ...); - RayObject result1 = Ray.call(Adder::add, adder, 1); - RayObject result2 = Ray.call(Adder::add, adder, 10); - result2.get(); // 11 \ No newline at end of file diff --git a/java/doc/api.rst b/java/doc/api.rst new file mode 100644 index 000000000..d7402deaf --- /dev/null +++ b/java/doc/api.rst @@ -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 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`` to indicate a result + from another ``Ray.call`` invocation. + +The returned object is labeled as ``RayObject`` 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 RayObject put(T object); + public static RayObject put(T obj, TM metadata); + +``RayObject.get/getMeta`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: java + + public class RayObject { + public T get() throws TaskExecutionException; + public 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 wait(RayList waitfor, int numReturns, int timeout); + public static WaitResult wait(RayList waitfor, int numReturns); + public static WaitResult wait(RayList 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`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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`` +^^^^^^^^^^^^^^ + +This is a list of ``RayObject``s, which inherits from ``List`` in Java. It +can be used as the type for both a return value and a parameter value. + +``RayMap`` +^^^^^^^^^^^^^^^^ + +A map of ``RayObject``s with each indexed using a label with type +``L``, inherited from ``Map``. 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 call_2(Func func, ...); + RayObjects3 call_3(Func func, ...); + RayObjects4 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 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 sayMultiRet() { + return new MultipleReturns2(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``s in ``RayList``. This is because Ray needs to know the +number of return values before the method is actually executed. + +.. code:: java + + RayList call_n(Func func, Integer returnCount, ...); + +Here is an example. + +.. code:: java + + public class ListRExample { + public static void main(String[] args) { + Ray.init(); + RayList ns = Ray.call_n(ListRExample::sayList, 10, 10); + for (int i = 0; i < 10; i++) { + RayObject obj = ns.Get(i); + Assert.assertTrue(i == obj.get()); + } + } + + @RayRemote + public static List sayList(Integer count) { + ArrayList 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`` in ``RayMap`` has a given label when +``Ray.call_n`` is made. + +.. code:: java + + RayMap call_n(Func func, Collection returnLabels, ...); + +Here is an example. + +.. code:: java + + public class MapRExample { + public static void main(String[] args) { + Ray.init(); + RayMap ns = Ray.call_n(MapRExample::sayMap, + Arrays.asList(1, 2, 4, 3), "n_futures_"); + for (Entry> ne : ns.EntrySet()) { + Integer key = ne.getKey(); + RayObject obj = ne.getValue(); + Assert.assertTrue(obj.get().equals("n_futures_" + key)); + } + } + + @RayRemote(externalIO = true) + public static Map sayMap(Collection ids, + String prefix) { + Map 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 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 obj = Ray.call(ListTExample::sayReadRayList, + (List)ints); + Assert.assertTrue(obj.get().equals(3)); + } + + @RayRemote + public static int sayReadRayList(List 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 = 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 Ray.call(Func func, RayActor actor, ...); + RayObject result1 = Ray.call(Adder::add, adder, 1); + RayObject result2 = Ray.call(Adder::add, adder, 10); + result2.get(); // 11 diff --git a/java/doc/installation.rst b/java/doc/installation.rst new file mode 100644 index 000000000..6adee9841 --- /dev/null +++ b/java/doc/installation.rst @@ -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 `_. + +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 \ No newline at end of file diff --git a/java/example/run.sh b/java/example/run.sh deleted file mode 100755 index cdf65a440..000000000 --- a/java/example/run.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/java/example/src/main/java/org/ray/example/HelloWorld.java b/java/example/src/main/java/org/ray/example/HelloWorld.java deleted file mode 100644 index 2335b0a54..000000000 --- a/java/example/src/main/java/org/ray/example/HelloWorld.java +++ /dev/null @@ -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 hello = Ray.call(HelloWorld::sayHello); - RayObject world = Ray.call(HelloWorld::sayWorld); - return Ray.call(HelloWorld::merge, hello, world).get(); - } -} diff --git a/java/pom.xml b/java/pom.xml index 1682449e4..89584b6ee 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -17,7 +17,7 @@ runtime-dev cli test - example + tutorial diff --git a/java/ray.config.ini b/java/ray.config.ini index 738228a39..c9630e75b 100644 --- a/java/ray.config.ini +++ b/java/ray.config.ini @@ -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/* = diff --git a/java/test_cluster.sh b/java/test_cluster.sh index 2c1a23953..a031fe335 100755 --- a/java/test_cluster.sh +++ b/java/test_cluster.sh @@ -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 diff --git a/java/tutorial/README.rst b/java/tutorial/README.rst new file mode 100644 index 000000000..e9b5c22c1 --- /dev/null +++ b/java/tutorial/README.rst @@ -0,0 +1,31 @@ +Ray Java Tutorial +================= + +- `Installation guide `_ +- `API document `_ + +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 `_: Define a remote function, and execute multiple remote functions in parallel. + +`Exercise 2 `_: Execute remote functions in parallel with some dependencies. + +`Exercise 3 `_: Call remote functions from within remote functions. + +`Exercise 4 `_: Use ``Ray.wait`` to ignore stragglers. + +`Exercise 5 `_: Use multiple heterogeneous return values. + +`Exercise 6 `_: Usage of ``RayList``. + +`Exercise 7 `_: Usage of ``RayMap``. + +`Exercise 8 `_: Actor Support of create Actor and call Actor method. diff --git a/java/example/pom.xml b/java/tutorial/pom.xml similarity index 95% rename from java/example/pom.xml rename to java/tutorial/pom.xml index 54e508fcd..f79701364 100644 --- a/java/example/pom.xml +++ b/java/tutorial/pom.xml @@ -11,10 +11,10 @@ 4.0.0 org.ray - ray-example + ray-tutorial - java example for ray - java example for ray + java tutorial + Tutorial of using Ray with Java jar @@ -94,4 +94,4 @@ - \ No newline at end of file + diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise01.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise01.java new file mode 100644 index 000000000..fc1ab8c66 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise01.java @@ -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 hello = Ray.call(Exercise01::sayHello); + RayObject 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(); + } + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise02.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise02.java new file mode 100644 index 000000000..734019790 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise02.java @@ -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 hello = Ray.call(Exercise02::sayHello); + RayObject 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(); + } + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise03.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise03.java new file mode 100644 index 000000000..b4c61796c --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise03.java @@ -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 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(); + } + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise04.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise04.java new file mode 100644 index 000000000..34ba5c883 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise04.java @@ -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 o1 = Ray.call(Exercise04::f1); + RayObject o2 = Ray.call(Exercise04::f2); + RayObject o3 = Ray.call(Exercise04::f3); + RayList 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 waitResult = Ray.wait(rayList, 2, 3000); + RayList readyOnes = waitResult.getReadyOnes(); + RayList 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(); + } + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise05.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise05.java new file mode 100644 index 000000000..09a8499d0 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise05.java @@ -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 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 sayMultiRet() { + return new MultipleReturns2(123, "123"); + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise06.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise06.java new file mode 100644 index 000000000..4d4e962a0 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise06.java @@ -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 ns = Ray.call_n(Exercise06::sayList, 10, 10); + for (int i = 0; i < 10; i++) { + RayObject 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 sayList(Integer count) { + ArrayList rets = new ArrayList<>(); + for (int i = 0; i < count; i++) { + rets.add(i); + } + return rets; + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise07.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise07.java new file mode 100644 index 000000000..d721fe291 --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise07.java @@ -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 ns = Ray.call_n(Exercise07::sayMap, + Arrays.asList(1, 2, 4, 3), "n_futures_"); + for (Map.Entry> ne : ns.EntrySet()) { + Integer key = ne.getKey(); + RayObject 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 sayMap(Collection ids, String prefix) { + Map ret = new HashMap<>(); + for (int id : ids) { + ret.put(id, prefix + id); + } + return ret; + } +} diff --git a/java/tutorial/src/main/java/org/ray/exercise/Exercise08.java b/java/tutorial/src/main/java/org/ray/exercise/Exercise08.java new file mode 100644 index 000000000..f1fb9629d --- /dev/null +++ b/java/tutorial/src/main/java/org/ray/exercise/Exercise08.java @@ -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 = Ray.create(Adder.class); + // Use `Ray.call(actor, parameters)` to call an actor method. + RayObject result1 = Ray.call(Adder::add, adder, 1); + RayObject 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; + } +}