简体   繁体   English

何时使用Akka,何时不使用?

[英]When to use Akka and when not to?

I'm currently in the situation that I'm actually making things more complicated by using Actors then when I don't. 我目前处于这样一种情况,我实际上是在不使用Actor的情况下使事情变得更加复杂。 I need to execute a lot of Http Requests without blocking the Main thread. 我需要执行很多Http请求而不阻塞主线程。 Since this is concurrency and I wanted to try something different then locks, I decided to go with Akka. 由于这是并发的,所以我想尝试一些不同于锁的方法,所以我决定选择Akka。 Now I'm in the situation that I'm doubting between two approaches. 现在,我在两种方法之间都感到怀疑。

Approach one (Create new Actors when it's in need): 方法一(在需要时创建新的Actor):

public class Main {
    public void start() {
        ActorSystem system = ActorSystem.create();

        // Create 5 Manager Actors (Currently the same Actor for all but this is different in actual practise)
        ActorRef managers = system.actorOf(new BroadcastPool(5).props(Props.create(Actor.class)));
        managers.tell(new Message(), ActorRef.noSender());
    }
}

public class Actor extends UntypedActor {

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof Message) {
            ActorRef ref = getContext().actorOf(new SmallestMailboxPool(10).props(Props.create(Actor.class)));

            // Repeat the below 10 times
            ref.tell(new Message2(), getSelf());
        } else if (message instanceof Message2) {
            // Execute long running Http Request
        }
    }
}

public final class Message {
    public Message() {
    }
}

public final class Message2 {
    public Message2() {
    }
}

Approach two (Create a whole lot of actors before hand and hope it's enough): 方法二(先创建大量演员并希望足够):

public class Main {
    public void start() {
        ActorSystem system = ActorSystem.create();

        ActorRef actors = system.actorOf(new SmallestMailboxPool(100).props(Props.create(Actor.class)));
        ActorRef managers = system.actorOf(new BroadcastPool(5).props(Props.create(() -> new Manager(actors))));

        managers.tell(new Message(), ActorRef.noSender());
    }
}

public class Manager extends UntypedActor {

    private ActorRef actors;

    public Manager(ActorRef actors) {
        this.actors = actors;
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof Message) {
            // Repeat 10 times
            actors.tell(new Message2(), getSelf());
        }
    }
}

public class Actor extends UntypedActor {

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof Message2) {
            // Http request
        }
    }
}

public final class Message {
    public Message() {
    }
}

public final class Message2 {
    public Message2() {
    }
}

So both approaches have up and down sides. 因此,这两种方法都有其优点。 One makes sure it can always handle new requests coming in, those never have to wait. 一个可以确保它始终可以处理传入的新请求,而不必等待。 But it leaves behind a lot of Actors that are never gonna be used. 但这留下了很多永远不会使用的演员。 Two on the hand reuses Actors but with the downside that it might not have enough of them and can't cope some time in the future and has to queue the messages. 一方面有两个重用Actor,但缺点是可能没有足够的Actor,将来无法应付某些时间,因此必须将消息排队。

What is the best approach of solving this and what is most common way people deal with this? 解决此问题的最佳方法是什么,人们处理此问题的最常用方法是什么?

If you think I could be doing this sort of stuff a lot better (with or without Akka) please tell me! 如果您认为我可以做得更好(带或不带Akka),请告诉我! I'm pretty new to Akka and would love to learn more about it. 我对Akka还是很陌生,很想了解更多有关它的信息。

Based on the given information, it looks like a typical example for task-based concurrency -- not for actor-based concurrency. 根据给定的信息,它看起来像是基于任务的并发的典型示例,而不是基于参与者的并发的典型示例。 Imagine you have a method for doing the HTTP request. 假设您有一种执行HTTP请求的方法。 The method fetches the given URL and returns an object without causing any data races on shared memory: 该方法获取给定的URL并返回一个对象,而不会引起共享内存上的任何数据争用:

private static Page loadPage(String url) {
    // ...
}

You can easily fetch the pages concurrently with an Executor . 您可以使用Executor轻松同时获取页面。 There are different kinds of Executors , eg you can use one with a fixed number of threads. 执行器种类繁多,例如,您可以使用一个具有固定数量线程的执行器。

public static void main(String... args) {
    ExecutorService executor = Executors.newFixedThreadPool(5);
    List<Future<Page>> futures = new ArrayList<>();
    // submit tasks
    for (String url : args) {
        futures.add(executor.submit(() -> loadPage(url)));
    }
    // access result of tasks (or wait until it is available)
    for (Future<Page> future : futures) {
        Page page = future.get();
        // ...
    }
    executor.shutdown();
}

There is no further synchronization required. 不需要进一步的同步。 The Executor framework takes care of that. 执行器框架负责这一点。

我会使用混合方法:预先创建相对较小的actor池,在需要时增加它,但保持池的大小受限(当连接过多时拒绝请求,以避免由于内存不足而导致崩溃)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM