123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- .. _cross_language:
- Cross-language programming
- ==========================
- This page will show you how to use Ray's cross-language programming feature.
- Setup the driver
- -----------------
- We need to set :ref:`code_search_path` in your driver.
- .. tabs::
- .. group-tab:: Python
- .. code-block:: python
- ray.init(job_config=ray.job_config.JobConfig(code_search_path="/path/to/code"))
- .. group-tab:: Java
- .. code-block:: bash
- java -classpath <classpath> \
- -Dray.address=<address> \
- -Dray.job.code-search-path=/path/to/code/ \
- <classname> <args>
- You may want to include multiple directories to load both Python and Java code for workers, if they are placed in different directories.
- .. tabs::
- .. group-tab:: Python
- .. code-block:: python
- ray.init(job_config=ray.job_config.JobConfig(code_search_path="/path/to/jars:/path/to/pys"))
- .. group-tab:: Java
- .. code-block:: bash
- java -classpath <classpath> \
- -Dray.address=<address> \
- -Dray.job.code-search-path=/path/to/jars:/path/to/pys \
- <classname> <args>
- Python calling Java
- -------------------
- Suppose we have a Java static method and a Java class as follows:
- .. code-block:: java
- package io.ray.demo;
- public class Math {
- public static int add(int a, int b) {
- return a + b;
- }
- }
- .. code-block:: java
- package io.ray.demo;
- // A regular Java class.
- public class Counter {
- private int value = 0;
- public int increment() {
- this.value += 1;
- return this.value;
- }
- }
- Then, in Python, we can call the above Java remote function, or create an actor
- from the above Java class.
- .. code-block:: python
- import ray
- ray.init(address="auto")
- # Define a Java class.
- counter_class = ray.java_actor_class(
- "io.ray.demo.Counter")
- # Create a Java actor and call actor method.
- counter = counter_class.remote()
- obj_ref1 = counter.increment.remote()
- assert ray.get(obj_ref1) == 1
- obj_ref2 = counter.increment.remote()
- assert ray.get(obj_ref2) == 2
- # Define a Java function.
- add_function = ray.java_function(
- "io.ray.demo.Math", "add")
- # Call the Java remote function.
- obj_ref3 = add_function.remote(1, 2)
- assert ray.get(obj_ref3) == 3
- ray.shutdown()
- Java calling Python
- -------------------
- Suppose we have a Python module as follows:
- .. code-block:: python
- # ray_demo.py
- import ray
- @ray.remote
- class Counter(object):
- def __init__(self):
- self.value = 0
- def increment(self):
- self.value += 1
- return self.value
- @ray.remote
- def add(a, b):
- return a + b
- .. note::
- * The function or class should be decorated by `@ray.remote`.
- Then, in Java, we can call the above Python remote function, or create an actor
- from the above Python class.
- .. code-block:: java
- package io.ray.demo;
- import io.ray.api.ObjectRef;
- import io.ray.api.PyActorHandle;
- import io.ray.api.Ray;
- import io.ray.api.function.PyActorClass;
- import io.ray.api.function.PyActorMethod;
- import io.ray.api.function.PyFunction;
- import org.testng.Assert;
- public class JavaCallPythonDemo {
- public static void main(String[] args) {
- Ray.init();
- // Define a Python class.
- PyActorClass actorClass = PyActorClass.of(
- "ray_demo", "Counter");
- // Create a Python actor and call actor method.
- PyActorHandle actor = Ray.actor(actorClass).remote();
- ObjectRef objRef1 = actor.task(
- PyActorMethod.of("increment", int.class)).remote();
- Assert.assertEquals(objRef1.get(), 1);
- ObjectRef objRef2 = actor.task(
- PyActorMethod.of("increment", int.class)).remote();
- Assert.assertEquals(objRef2.get(), 2);
- // Call the Python remote function.
- ObjectRef objRef3 = Ray.task(PyFunction.of(
- "ray_demo", "add", int.class), 1, 2).remote();
- Assert.assertEquals(objRef3.get(), 3);
- Ray.shutdown();
- }
- }
- Cross-language data serialization
- ---------------------------------
- The arguments and return values of ray call can be serialized & deserialized
- automatically if their types are the following:
- - Primitive data types
- =========== ======= =======
- MessagePack Python Java
- =========== ======= =======
- nil None null
- bool bool Boolean
- int int Short / Integer / Long / BigInteger
- float float Float / Double
- str str String
- bin bytes byte[]
- =========== ======= =======
- - Basic container types
- =========== ======= =======
- MessagePack Python Java
- =========== ======= =======
- array list Array
- =========== ======= =======
- - Ray builtin types
- - ActorHandle
- .. note::
- * Be aware of float / double precision between Python and Java. If Java use a
- float type to receive the input argument, the double precision Python data
- will be reduced to float precision in Java.
- * BigInteger can support max value of 2^64-1, please refer to:
- https://github.com/msgpack/msgpack/blob/master/spec.md#int-format-family.
- If the value larger than 2^64-1, then transfer the BigInteger:
- - From Java to Python: *raise an exception*
- - From Java to Java: **OK**
- The following example shows how to pass these types as parameters and how to
- return return these types.
- You can write a Python function which returns the input data:
- .. code-block:: python
- # ray_serialization.py
- import ray
- @ray.remote
- def py_return_input(v):
- return v
- Then you can transfer the object from Java to Python, then returns from Python
- to Java:
- .. code-block:: java
- package io.ray.demo;
- import io.ray.api.ObjectRef;
- import io.ray.api.Ray;
- import io.ray.api.function.PyFunction;
- import java.math.BigInteger;
- import org.testng.Assert;
- public class SerializationDemo {
- public static void main(String[] args) {
- Ray.init();
- Object[] inputs = new Object[]{
- true, // Boolean
- Byte.MAX_VALUE, // Byte
- Short.MAX_VALUE, // Short
- Integer.MAX_VALUE, // Integer
- Long.MAX_VALUE, // Long
- BigInteger.valueOf(Long.MAX_VALUE), // BigInteger
- "Hello World!", // String
- 1.234f, // Float
- 1.234, // Double
- "example binary".getBytes()}; // byte[]
- for (Object o : inputs) {
- ObjectRef res = Ray.task(
- PyFunction.of("ray_serialization", "py_return_input", o.getClass()),
- o).remote();
- Assert.assertEquals(res.get(), o);
- }
- Ray.shutdown();
- }
- }
- Cross-language exception stacks
- -------------------------------
- Suppose we have a Java package as follows:
- .. code-block:: java
- package io.ray.demo;
- import io.ray.api.ObjectRef;
- import io.ray.api.Ray;
- import io.ray.api.function.PyFunction;
- public class MyRayClass {
- public static int raiseExceptionFromPython() {
- PyFunction<Integer> raiseException = PyFunction.of(
- "ray_exception", "raise_exception", Integer.class);
- ObjectRef<Integer> refObj = Ray.task(raiseException).remote();
- return refObj.get();
- }
- }
- and a Python module as follows:
- .. code-block:: python
- # ray_exception.py
- import ray
- @ray.remote
- def raise_exception():
- 1 / 0
- Then, run the following code:
- .. code-block:: python
- # ray_exception_demo.py
- import ray
- ray.init(address="auto")
- obj_ref = ray.java_function(
- "io.ray.demo.MyRayClass",
- "raiseExceptionFromPython").remote()
- ray.get(obj_ref) # <-- raise exception from here.
- ray.shutdown()
- The exception stack will be:
- .. code-block:: text
- Traceback (most recent call last):
- File "ray_exception_demo.py", line 10, in <module>
- ray.get(obj_ref) # <-- raise exception from here.
- File "ray/worker.py", line 1425, in get
- raise value
- ray.exceptions.CrossLanguageError: An exception raised from JAVA:
- io.ray.runtime.exception.RayTaskException: (pid=92253, ip=10.15.239.68) Error executing task df5a1a828c9685d3ffffffff01000000
- at io.ray.runtime.task.TaskExecutor.execute(TaskExecutor.java:167)
- Caused by: io.ray.runtime.exception.CrossLanguageException: An exception raised from PYTHON:
- ray.exceptions.RayTaskError: ray::raise_exception() (pid=92252, ip=10.15.239.68)
- File "python/ray/_raylet.pyx", line 482, in ray._raylet.execute_task
- File "ray_exception.py", line 7, in raise_exception
- 1 / 0
- ZeroDivisionError: division by zero
|