假设有一个很耗时的运算,单台机器已经没法满足需求,这时你可以想到由多台计算机协作完成。具体怎么做呢。
举个很简单的例子,假设这个耗时的运算是从1加到100000,你现在有两台服务器,可以让这两台服务器分别完成从1加到50000,和从50001加到100000,然后本机完成这两个结果之和。
两台服务器分别启动两个akka Server,同时还有一个CalcActor。这个计算actor接收两个参数:Integer start和Integer end,可以从start一直加到end,最后将结果返回给发送者:getSender().tell(result)。
@Log4j
class CalcActor
extends UntypedActor { @Override
void onReceive(Object message) { log.debug "
CalcActor received: ${message}----self:${getSelf()},sender:${getSender()}"
if (message
instanceof String) { String[] args = message.split("
,")
int start = Integer.parseInt(args[0])
int end = Integer.parseInt(args[1])
int result = 0 println("
start calc:" + start + "
upto " + end) start.upto(end) { result += it } sleep(5000) //模拟还要额外耗时5秒 println("
result:" + result) getSender().tell(result) }
else { unhandled(message) } } }
两个服务器分别为: AkkaServerApp serverA =
new AkkaServerApp("
sc", "
10.68.3.122", 8888, "
calc")
//AkkaSystemName为sc,ip为10.68.3.122,端口为8888,serviceName为calc。 AkkaServerApp serverA =
new AkkaServerApp("
sp", "
10.68.3.124", 8888, "
calc")
//AkkaSystemName为sp,ip为10.68.3.124,端口为8888,serviceName为calc。
主要的代码在客户端:
public
static
void main(String[] args)
throws Exception {
final AkkaServerApp app =
new AkkaServerApp("
xwc", "
127.0.0.1", 6666, "
client");
//客户端akka配置 ActorRef remoteCalcA1 = app.getSystem().actorOf(
new Props(CalcActor.
class)..withDeploy(
new Deploy(
new RemoteScope(
new Address("
akka", "
sc", "
10.68.3.122", 8888)))), "
clientCalcA1");
//将CalcActor发布到远程10.68.3.122上 ActorRef remoteCalcA2 = app.getSystem().actorOf(
new Props(CalcActor.
class)..withDeploy(
new Deploy(
new RemoteScope(
new Address("
akka", "
sc", "
10.68.3.122", 8888)))), "
clientCalcA2");
//将CalcActor发布到远程10.68.3.124上
final List<Future<Double>> frs =
new ArrayList<Future<Double>>();
//异步返回结果Future存放在list中 //tell只请求,是否响应它完全不知道。ask是请求,并明确知道未来会相应。
// remoteCalcA.tell("1,10000", app.getServerActor());
// remoteCalcB.tell("10001,20000", app.getServerActor()); Future f1 = akka.pattern.Patterns.ask(remoteCalcA1, "
1,50000", 150000);
//让远程122计算从1加到50000,超时时间为150秒 Future f2 = akka.pattern.Patterns.ask(remoteCalcA1, "
50001,100000", 150000);
//并发地让远程124计算从50001加到100000,超时时间150秒 frs.add(f1); frs.add(f2); Future<Iterable<Double>> future = Futures.sequence(frs, app.getSystem().dispatcher());将未来返回的结果转换成Future<Iterable<Double>> Future<Double> fr = future.map(
new Mapper<Iterable<Double>, Double>() { @Override
public Double apply(Iterable<Double> parameter) { Double result = 0d;
for (Double s : parameter) {
//计算两个服务器返回的结果 result += s; }
return result; } }); fr.onSuccess(
new OnSuccess<Double>() { @Override
public
void onSuccess(Double result) { System.out.println("
云计算返回结果-----" + result); } }); }
还可以让服务器并发处理:把给从1加到50000的任务分成5个线程并行处理:1..10000,10001..20000,20001..30000,30001..40000,40001..50000,这样能更好地提高效率。
如果按上面的方法仅仅是发布多个remote actor:
ActorRef remoteCalcAn = app.getSystem().actorOf(new Props(CalcActor.class)..withDeploy(new Deploy(new RemoteScope(new Address("akka", "sc", "10.68.3.122", 8888)))), "clientCalcAn");
是没法提高效率的,因为这时的CalcActor是单线程的,它只会先接收1..10000,处理完后再接收10001..20000并处理。。。。。
使其能够并行处理很简单,创建remoteActor时加上withRoute即可:
ActorRef remoteCalcAn = app.getSystem().actorOf(
new Props(CalcActor.
class).withRouter(
new RoundRobinRouter(5)).withDeploy(
new Deploy(
new RemoteScope(
new Address("
akka", "
sc", "
10.68.3.122", 8888)))), "
clientCalcAn");
//RoundRobinRouter的参数5可以理解为分配5个线程并行处理
代码跟上面基本相同
public
static
void main(String[] args)
throws Exception {
final AkkaServerApp app =
new AkkaServerApp("
xwc", "
127.0.0.1", 6666, "
client"); ActorRef remoteCalcA1 = app.getSystem().actorOf(
new Props(CalcActor.
class).withRouter(
new RoundRobinRouter(4)).withDeploy(
new Deploy(
new RemoteScope(
new Address("
akka", "
sc", "
10.68.3.122", 8888)))), "
clientCalcA1"); ActorRef remoteCalcB1 = app.getSystem().actorOf(
new Props(CalcActor.
class).withRouter(
new RoundRobinRouter(4)).withDeploy(
new Deploy(
new RemoteScope(
new Address("
akka", "
sp", "
10.68.3.124", 8888)))), "
clientCalcB1");
final List<Future<Double>> frs =
new ArrayList<Future<Double>>(); Future f1 = akka.pattern.Patterns.ask(remoteCalcA1, "
1,10000", 150000); Future f2 = akka.pattern.Patterns.ask(remoteCalcA1, "
10001,20000", 150000); Future f3 = akka.pattern.Patterns.ask(remoteCalcA1, "
20001,30000", 150000); Future f4 = akka.pattern.Patterns.ask(remoteCalcA1, "
30001,40000", 150000); Future f5 = akka.pattern.Patterns.ask(remoteCalcB1, "
40001,50000", 150000); Future f6 = akka.pattern.Patterns.ask(remoteCalcB1, "
50001,60000", 150000); Future f7 = akka.pattern.Patterns.ask(remoteCalcB1, "
60001,70000", 150000); Future f8 = akka.pattern.Patterns.ask(remoteCalcB1, "
70001,80000", 150000); frs.add(f1); frs.add(f2); frs.add(f3); frs.add(f4); frs.add(f5); frs.add(f6); frs.add(f7); frs.add(f8); Future<Iterable<Double>> future = Futures.sequence(frs, app.getSystem().dispatcher()); Future<Double> fr = future.map(
new Mapper<Iterable<Double>, Double>() { @Override
public Double apply(Iterable<Double> parameter) { Double result = 0d;
for (Double s : parameter) { result += s; }
return result; } }); fr.onSuccess(
new OnSuccess<Double>() { @Override
public
void onSuccess(Double result) { System.out.println("
云计算返回从1加到80000的结果-----" + result); } }); }