[java] support creating an actor with parameters (#2817)

Previously `Ray.createActor` only support creating an actor without any parameter. This PR adds the support for creating an actor with parameters. Moreover, besides using a constructor, it's now also allowed to create an actor with a factory method. For more usage, prefer refer to `ActorTest.java`.
This commit is contained in:
Hao Chen
2018-09-04 00:53:03 +08:00
committed by Robert Nishihara
parent b37a283053
commit 9d655721e5
27 changed files with 1131 additions and 680 deletions
@@ -14,7 +14,7 @@ public class ActorPressTest extends RayBenchmarkTest {
@Test
public void singleLatencyTest() {
int times = 10;
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder.class);
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder::new);
super.singleLatencyTest(times, adder);
}
@@ -22,7 +22,7 @@ public class ActorPressTest extends RayBenchmarkTest {
public void maxTest() {
int clientNum = 2;
int totalNum = 20;
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder.class);
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder::new);
PressureTestParameter pressureTestParameter = new PressureTestParameter();
pressureTestParameter.setClientNum(clientNum);
pressureTestParameter.setTotalNum(totalNum);
@@ -36,7 +36,7 @@ public class ActorPressTest extends RayBenchmarkTest {
int clientNum = 2;
int totalQps = 2;
int duration = 3;
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder.class);
RayActor<ActorPressTest.Adder> adder = Ray.createActor(ActorPressTest.Adder::new);
PressureTestParameter pressureTestParameter = new PressureTestParameter();
pressureTestParameter.setClientNum(clientNum);
pressureTestParameter.setTotalQps(totalQps);
@@ -16,40 +16,61 @@ public class ActorTest {
@RayRemote
public static class Counter {
private int value = 0;
private int value;
public int incr(int delta) {
public Counter(int initValue) {
this.value = initValue;
}
public int getValue() {
return value;
}
public int increase(int delta) {
value += delta;
return value;
}
}
@Test
public void testCreateAndCallActor() {
// Test creating an actor from a constructor
RayActor<Counter> actor = Ray.createActor(Counter::new, 1);
Assert.assertNotEquals(actor.getId(), UniqueId.NIL);
// Test calling an actor
Assert.assertEquals(Integer.valueOf(1), Ray.call(Counter::getValue, actor).get());
Assert.assertEquals(Integer.valueOf(11), Ray.call(Counter::increase, actor, 10).get());
}
@RayRemote
public static Counter factory(int initValue) {
return new Counter(initValue);
}
@Test
public void testCreateActorFromFactory() {
// Test creating an actor from a factory method
RayActor<Counter> actor = Ray.createActor(ActorTest::factory, 1);
Assert.assertNotEquals(actor.getId(), UniqueId.NIL);
// Test calling an actor
Assert.assertEquals(Integer.valueOf(1), Ray.call(Counter::getValue, actor).get());
}
@RayRemote
public static int testActorAsFirstParameter(RayActor<Counter> actor, int delta) {
RayObject<Integer> res = Ray.call(Counter::incr, actor, delta);
RayObject<Integer> res = Ray.call(Counter::increase, actor, delta);
return res.get();
}
@RayRemote
public static int testActorAsSecondParameter(int delta, RayActor<Counter> actor) {
RayObject<Integer> res = Ray.call(Counter::incr, actor, delta);
RayObject<Integer> res = Ray.call(Counter::increase, actor, delta);
return res.get();
}
@Test
public void testCreateAndCallActor() {
// Test creating an actor
RayActor<Counter> actor = Ray.createActor(Counter.class);
Assert.assertNotEquals(actor.getId(), UniqueId.NIL);
// Test calling an actor
RayFunc2<Counter, Integer, Integer> f = Counter::incr;
Assert.assertEquals(Integer.valueOf(1), Ray.call(f, actor, 1).get());
Assert.assertEquals(Integer.valueOf(11), Ray.call(Counter::incr, actor, 10).get());
}
@Test
public void testPassActorAsParameter() {
RayActor<Counter> actor = Ray.createActor(Counter.class);
RayActor<Counter> actor = Ray.createActor(Counter::new, 0);
RayFunc2<RayActor, Integer, Integer> f = ActorTest::testActorAsFirstParameter;
Assert.assertEquals(Integer.valueOf(1),
Ray.call(ActorTest::testActorAsFirstParameter, actor, 1).get());
@@ -1,46 +0,0 @@
package org.ray.api.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ray.api.Ray;
import org.ray.api.annotation.RayRemote;
@RunWith(MyRunner.class)
public class EchoTest {
@RayRemote
public static String hi() {
return "hi";
}
@RayRemote
public static String who(String who) {
return who;
}
@RayRemote
public static String recho(String pre, String who) {
return pre + ", " + who + "!";
}
@Test
public void test() {
long startTime = 0;
long endTime = 0;
for (int i = 0; i < 100; i++) {
startTime = System.nanoTime();
String ret = echo("Ray++" + i);
endTime = System.nanoTime();
System.out.println("echo: " + ret + " , total time is " + (endTime - startTime));
}
}
public String echo(String who) {
return Ray.call(
EchoTest::recho,
Ray.call(EchoTest::hi),
Ray.call(EchoTest::who, who)
).get();
}
}
@@ -1,38 +1,44 @@
package org.ray.api.test;
import java.lang.reflect.Method;
import java.lang.reflect.Executable;
import org.junit.Assert;
import org.junit.Test;
import org.ray.api.function.RayFunc3;
import org.ray.api.function.RayFunc2;
import org.ray.util.MethodId;
import org.ray.util.logger.RayLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MethodIdTest {
public static <T0, T1, T2, R0> MethodId fromLambda(RayFunc3<T0, T1, T2, R0> f) {
MethodId mid = MethodId.fromSerializedLambda(f, true);
return mid;
}
public static MethodId fromClass(Method method) {
return MethodId.fromMethod(method);
}
private static final Logger LOGGER = LoggerFactory.getLogger(MethodIdTest.class);
@Test
public void testMethodId2From() throws Exception {
MethodId m1 = fromLambda(MethodIdTest::call);
Method m = MethodIdTest.class.getDeclaredMethod("call", new Class[]{long.class, String.class});
MethodId m2 = fromClass(m);
RayLog.core.info(m1.toString());
public void testNormalMethod() throws Exception {
RayFunc2<Integer, String, String> f = MethodIdTest::foo;
MethodId m1 = MethodId.fromSerializedLambda(f);
Executable e = MethodIdTest.class.getDeclaredMethod("foo", int.class, String.class);
MethodId m2 = MethodId.fromExecutable(e);
LOGGER.info("{}, {}", m1, m2);
Assert.assertEquals(m1, m2);
}
public String call(long v, String s) {
for (int i = 0; i < 100; i++) {
v += i;
}
RayLog.core.info("call:" + v);
return String.valueOf(v);
@Test
public void testConstructor() throws Exception {
RayFunc2<Integer, String, Foo> f = Foo::new;
MethodId m1 = MethodId.fromSerializedLambda(f);
Executable e = Foo.class.getConstructor(int.class, String.class);
MethodId m2 = MethodId.fromExecutable(e);
LOGGER.info("{}, {}", m1, m2);
Assert.assertEquals(m1, m2);
}
}
public static String foo(int a, String b) {
return a + b;
}
public static class Foo {
public Foo(int a, String b) {}
}
}
@@ -4,10 +4,13 @@ import org.junit.Assert;
import org.junit.Test;
import org.ray.api.annotation.RayRemote;
import org.ray.spi.model.RayActorMethods;
import org.ray.util.logger.RayLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RayActorMethodsTest {
private static final Logger LOGGER = LoggerFactory.getLogger(RayActorMethodsTest.class);
@RayRemote
public static class ExampleActor {
@@ -22,7 +25,7 @@ public class RayActorMethodsTest {
public void testActorMethods() {
RayActorMethods methods = RayActorMethods
.fromClass(ExampleActor.class.getName(), RayActorMethodsTest.class.getClassLoader());
RayLog.core.info(methods.toString());
LOGGER.info(methods.toString());
Assert.assertEquals(methods.functions.size(), 2);
Assert.assertEquals(methods.staticFunctions.size(), 1);
}
@@ -1,18 +1,44 @@
package org.ray.api.test;
import java.lang.reflect.Constructor;
import org.junit.Assert;
import org.junit.Test;
import org.ray.spi.model.RayMethod;
import org.ray.spi.model.RayTaskMethods;
import org.ray.util.logger.RayLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RayTaskMethodsTest {
@Test
public void testTask() throws Exception {
RayTaskMethods methods = RayTaskMethods
.fromClass(EchoTest.class.getName(), RayTaskMethodsTest.class.getClassLoader());
RayLog.core.info(methods.toString());
Assert.assertEquals(methods.functions.size(), 3);
private static final Logger LOGGER = LoggerFactory.getLogger(RayTaskMethodsTest.class);
private static class Foo {
public Foo() {}
public Foo(int x) {}
public static void f1() {}
public void f2() {}
}
}
@Test
public void testTask() {
RayTaskMethods methods = RayTaskMethods
.fromClass(Foo.class.getName(), Foo.class.getClassLoader());
LOGGER.info(methods.toString());
int numMethods = 0;
int numConstructors = 0;
for (RayMethod m : methods.functions.values()) {
if (m.isConstructor()) {
numConstructors += 1;
} else {
numMethods += 1;
}
}
Assert.assertEquals(numMethods, 1);
Assert.assertEquals(numConstructors, 2);
}
}
@@ -66,12 +66,12 @@ public class ResourcesManagementTest {
public void testActors() {
Assume.assumeTrue(AbstractRayRuntime.getParams().use_raylet);
// This is a case that can satisfy required resources.
RayActor<ResourcesManagementTest.Echo1> echo1 = Ray.createActor(Echo1.class);
RayActor<ResourcesManagementTest.Echo1> echo1 = Ray.createActor(Echo1::new);
final RayObject<Integer> result1 = Ray.call(Echo1::echo, echo1, 100);
Assert.assertEquals(100, (int) result1.get());
// This is a case that can't satisfy required resources.
RayActor<ResourcesManagementTest.Echo2> echo2 = Ray.createActor(Echo2.class);
RayActor<ResourcesManagementTest.Echo2> echo2 = Ray.createActor(Echo2::new);
final RayObject<Integer> result2 = Ray.call(Echo2::echo, echo2, 100);
WaitResult<Integer> waitResult = Ray.wait(ImmutableList.of(result2), 1, 1000);