简体   繁体   English

Akka演员被另一个执行CPU密集型工作的演员阻止

[英]Akka actor blocked by another actor running CPU-intensive job

I have an ActorSystem which has three actors, a MasterActor, a PrinterActor and a BlockerActor: 我有一个ActorSystem,它具有三个actor,一个MasterActor,一个PrinterActor和一个BlockerActor:

The PrinterActor simply sleeps for one second then prints out something: PrinterActor只需睡眠一秒钟,然后打印出一些内容:

public class PrinterActor extends UntypedActor {

    @Override
    public void onReceive(Object msg) throws Exception {        
        Thread.sleep(1000);
        System.out.println("elapsed time is " + (System.currentTimeMillis()-(Long)msg));
    }
}

The BlockerActor does some CPU-intensive work: BlockerActor完成一些CPU密集型工作:

public class BlockerActor extends UntypedActor {

    @Override
    public void onReceive(Object msg) throws Exception {
        long count=0;
        for (int i=0; i<5000; i++) {
            for (int j=0; j<1000000000; j++) {
                count++;
            }
        }
        System.out.println("count is " + count);
     }
}

The MasterActor creates the above two actors then tells them to start working at the same time: MasterActor创建上述两个actor,然后告诉他们同时开始工作:

public class MasterActor extends UntypedActor {

    @Override
    public void onReceive(Object msg) throws Exception {
        ActorRef printer = getContext().actorOf(Props.create(PrinterActor.class), "printerActor");
        ActorRef blocker = getContext().actorOf(Props.create(BlockerActor.class), "blockerActor");

        blocker.tell("start", getSelf());
        printer.tell(System.currentTimeMillis(), getSelf());
    }
}

The main method instantiates an ActorSystem, creates a MasterActor under it then sends the actor a start message. 主要方法实例化ActorSystem,在其下创建MasterActor,然后向actor发送启动消息。

public class App {
    public static void main( String[] args ) {
        ActorSystem actorSystem = ActorSystem.create("Test");
        ActorRef master = actorSystem.actorOf(Props.create(MasterActor.class), "masterActor");
        master.tell("start", null);
    }
}

I expected the PrinterActor to finish fast but this was not the case. 我希望PrinterActor快速完成,但事实并非如此。 See the output below: 请参见下面的输出:

count is 5000000000000
elapsed time is 106856

It looks to me the PrinterActor didn't actually get a separate thread but was sharing a single thread with other two actors in the system. 在我看来,PrinterActor实际上并没有获得单独的线程,而是与系统中的其他两个actor共享了一个线程。 I'm having this impression because if I change the BlockerActor's implementation to: 我有这种印象,因为如果我将BlockerActor的实现更改为:

public class BlockerActor extends UntypedActor {

    @Override
    public void onReceive(Object msg) throws Exception {
        Thread.sleep(60 * 1000);
    }
}

the PrinterActor would run much faster: PrinterActor将运行得更快:

elapsed time is 1004

Note that I did not configure any dispatcher for my actors. 请注意,我没有为演员配置任何调度程序。 So they should all be using the system's default dispatcher which has a pool of 3.0 (default parallelism-factor) * number of CPUs (8 cores in my machine) = 24 threads. 因此,他们都应该使用系统的默认调度程序,该调度程序的池为3.0(默认并行因子)* CPU数量(本机中为8个内核)= 24个线程。 I even tried to give the PrinterActor a PinnedDispatcher (dedicated thread) but still couldn't get the PrinterActor to speed up when my BlockerActor was working hard. 我什至试图给PrinterActor一个PinnedDispatcher(专用线程),但是当我的BlockerActor努力工作时,仍然无法让PrinterActor加速。

Now I'm really confused. 现在我真的很困惑。 Aren't you suppose to get some degree of parallelism when using actors like this? 当使用这样的参与者时,您不是应该获得某种程度的并行性吗? Is this an expected behavior of Akka or did I do anything wrong? 这是Akka的预期行为,还是我做错了什么?

PS: I ran my program in Eclipse with Akka 2.3.6 PS:我使用Akka 2.3.6在Eclipse中运行了程序

The issue could be with Thread.sleep as there are platform/implementation related issues. 该问题可能与Thread.sleep有关,因为存在与平台/实现相关的问题。

http://www.jwrapper.com/blog/worst-bug-ever-java-sleeps-3-orders-of-magnitude-too-long https://community.oracle.com/thread/2576985 http://www.jwrapper.com/blog/worst-bug-ever-java-sleeps-3-orders-of-magnitude-too-long https://community.oracle.com/thread/2576985

I tried your example in Scala and did not experience any additional blocking for the PrintActor. 我在Scala中尝试了您的示例,并且没有遇到PrintActor的任何其他阻塞。

You can also add another printout for the "internal" execution time to verify if Thread.sleep is the problem. 您还可以在“内部”执行时间添加另一个打印输出,以验证Thread.sleep是否是问题所在。

elapsed time is 1005 (external) 经过时间为1005(外部)

elapsed time is 1007 (internal) 经过的时间是1007(内部)

counter is 5000000000 计数器是50亿

package Actors

import akka.actor.{ActorSystem, Actor, Props}

class PrintActor extends Actor {
  override def receive = {
    case externalStartTime: Long =>
      val internalStartTime = System.currentTimeMillis()
      Thread.sleep(1000)
      println(s"elapsed time is ${System.currentTimeMillis() - externalStartTime} (external)")
      println(s"elapsed time is ${System.currentTimeMillis() - internalStartTime} (internal)")
    case _ => throw new IllegalArgumentException
  }
}

class BlockerActor extends Actor {
  override def receive = {
    case "start" =>
      var counter = 0L
      for (i <- 1 to 5000) {
        for (j <- 1 to 1000000) { // 1000000000
          counter += 1
        }
      }
      println(s"counter is $counter")
    case _ => throw new IllegalArgumentException
  }
}

class MasterActor extends Actor {
  override def receive = {
    case "start" =>
      val printer = context.actorOf(Props[PrintActor], "printerActor")
      val blocker = context.actorOf(Props[BlockerActor], "blockerActor")
      blocker.tell("start", self)
      printer.tell(System.currentTimeMillis(), self)
    case _ => throw new IllegalArgumentException
  }
}

object App {
  def main (args: Array[String]) {
    val actorSystem = ActorSystem("Test")
    val master = actorSystem.actorOf(Props[MasterActor], "masterActor")
    master.tell("start", null)
    actorSystem.shutdown()
  }
}

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

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