Actor ask请求

向一个actor发送消息,除使用tell,还可以使用ask进行请求.

tell异步发送消息:它用于异步发送消息。它不会等待并阻止线程发送消息;提供了最佳的并发性和可伸缩性。

Ask用于异步发送消息:它返回一个Future, 表示可能的答复。如果Actor没有回复并完成未来, 它将在超时期限后过期。超时时间过后, 它将引发TimeoutException。

forward为消息转发:其作用主要是能保持最开发发送的actor,如A发送消息M至B,B中forward至C,则C中获取消息的sender仍然为A

下面介绍下ask的使用:

辅助类

消息

package com.zte.sunquan.demo.actor.ask;

import java.io.Serializable;

/**
 * Created by on 2017/10/10.
 */
public class Message implements Serializable{
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Message{");
        sb.append("id=").append(id);
        sb.append('}');
        return sb.toString();
    }
}

打印

package com.zte.sunquan.demo.actor.ask;

import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.actor.ReceiveTimeout;

import java.time.Instant;

/**
 * Created by on 2017/9/19.
 */
public class PrintActor extends AbstractActor {
    public static Props props(){
        return Props.create(PrintActor.class);
    }
    @Override
    public Receive createReceive() {
        return receiveBuilder().match(String.class,
                s -> {
                    System.out.println(s + ":" + Instant.now());
                })
                .match(ReceiveTimeout.class, t ->
                        System.out.println("ReceiveTimeout")
                ).match(Throwable.class, t ->
                                System.out.println("Throwable")
//                        breaker.fail()
                )
                .build();
    }

}


处理actor

package com.zte.sunquan.demo.actor.ask;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.DeadLetterActorRef;
import akka.actor.Props;
import akka.dispatch.Futures;
import akka.dispatch.Mapper;
import akka.dispatch.OnComplete;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.google.common.collect.Lists;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;

import java.util.Iterator;
import java.util.concurrent.TimeUnit;

import static akka.pattern.Patterns.pipe;

/**
 * Created by sunquan on 2017/10/10.
 */
public class ProcessActor extends AbstractActor {
    final Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS));
    private ActorRef sub1Actor = getContext().actorOf(ProcessSub1Actor.props());
    private ActorRef sub2Actor = getContext().actorOf(ProcessSub2Actor.props());
    private ActorRef printActor = getContext().actorOf(PrintActor.props());

    public static Props props() {
        return Props.create(ProcessActor.class);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(String.class, p -> {
            System.out.println("ProcessActor receive:" + p);
//            Thread.sleep(6000);
            getSender().tell("process success", getSelf());
        }).match(Message.class, p -> {
            //多actor参与计算-->最后合并结果
            Future<Object> process1 = Patterns.ask(sub1Actor, p, timeout);
            Future<Object> process2 = Patterns.ask(sub2Actor, p, timeout);

            //主要是为了控制返回结果顺序
            final Future<Iterable<Object>> aggregate = Futures.sequence(
                    Lists.newArrayList(process1, process2),
                    getContext().system().dispatcher());
            //可使用get直接获取结果,这里使用map对结果进行转换
            final Future<String> aggResult = aggregate.map(
                    new Mapper<Iterable<Object>, String>() {
                        public String apply(Iterable<Object> coll) {
                            final Iterator<Object> it = coll.iterator();
                            final String process1Result = (String) it.next();
                            final String process2Result = (String) it.next();
                            return process1Result + "---" + process2Result;
                        }
                    }, getContext().system().dispatcher());

            // aggregated result is piped to another actor
            if (getSender() == null || getSender() == ActorRef.noSender()
                    || getSender() instanceof DeadLetterActorRef) {

                aggResult.onComplete(new OnComplete<String>() {
                    @Override
                    public void onComplete(Throwable throwable, String s) throws Throwable {
                        if (throwable == null&&aggResult.isCompleted())
                            System.out.println("Result:" + aggResult.value());
                        else
                            System.out.println(throwable);
                    }
                }, getContext().system().dispatcher());
            } else {
//                pipe(aggResult, getContext().system().dispatcher()).to(
//                        printActor);
                pipe(aggResult, getContext().system().dispatcher()).to(
                        getSender());
            }
        })
                .build();
    }
}

package com.zte.sunquan.demo.actor.ask;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;

import java.util.concurrent.TimeUnit;

/**
 * Created by x on 2017/9/18.
 */
public class ProcessSub1Actor extends AbstractActor {
    public static Props props() {
        return Props.create(ProcessSub1Actor.class);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(Message.class,(content)->{
            System.out.println("ProcessSub1Actor process:"+content);
//            TimeUnit.SECONDS.sleep(4);
            getSender().tell("ProcessSub1Actor result:"+content, ActorRef.noSender());
        }).build();
    }
}

package com.zte.sunquan.demo.actor.ask;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;

import java.util.concurrent.TimeUnit;

/**
 * Created by x on 2017/9/18.
 */
public class ProcessSub2Actor extends AbstractActor {
    public static Props props() {
        return Props.create(ProcessSub2Actor.class);
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(Message.class,(content)->{
            System.out.println("ProcessSub2Actor process:"+content);
//            TimeUnit.SECONDS.sleep(4);
            getSender().tell("ProcessSub2Actor result:"+content, ActorRef.noSender());

        }).build();
    }
}


上面代码关键处,都包含了注释

测试用例:

package com.zte.sunquan.demo.actor.ask;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.dispatch.Mapper;
import akka.dispatch.OnComplete;
import akka.pattern.Patterns;
import akka.util.Timeout;
import org.junit.Test;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Created by x on 2017/10/10.
 */
public class ProcessActorTest {

    @Test
    public void startMessageTest() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
        ActorSystem system = ActorSystem.create();
        ActorRef myActor = system.actorOf(ProcessActor.props());
        ActorRef printActor = system.actorOf(PrintActor.props());
//        myActor.tell(new Message(), printActor);
        myActor.tell(new Message(), ActorRef.noSender());
        latch.await();
    }

    @Test
    public void startTest() throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);
        Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
        ActorSystem system = ActorSystem.create();
        ActorRef myActor = system.actorOf(ProcessActor.props());

        //使用ask发送消息,actor处理完,必须有返回(超时时间5秒)
        Future<Object> ask = Patterns.ask(myActor, "Hello,world", t);

        ask.onComplete(new OnComplete<Object>() {
            @Override
            public void onComplete(Throwable throwable, Object o) throws Throwable {
                if (throwable != null) {
                    //如果处理延迟大于ask参数
                    //akka.pattern.AskTimeoutException:
                    // Ask timed out on [Actor[akka://default/user/$a#2060184193]] after [5000 ms].
                    // Sender[null] sent message of type "java.lang.String".
                    // 从上一句话判断,处理函数一定要将string传递
                    System.out.println(throwable);

                } else {
                    System.out.println(o);
                }
            }
        }, system.dispatcher());

        //对结果进行取map (无法处理异常)
        ask.map(new Mapper<Object, Object>() {
            @Override
            public Object apply(Object o) {
                System.out.println("apply ask:" + o);
                return "end";
            }
        }, system.dispatcher());
//        System.out.println(ask.value().get().get());
        latch.await();
    }
}


在接收到Message后,通过ask分别发送消息到sub1和sub2,然后处理返回结果,在sender存在情况下pipe,i不存在则注释回调函数,在回调中处理结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值