如何检查akka应用程序中配置的调度程序

时间:2017-02-22 16:05:30

标签: multithreading akka

我在conf文件中有以下条目。但是我不确定这个调度程序设置是否被提取以及使用了什么样的最终并行度值

        akka{
      actor{
        default-dispatcher {
              type = Dispatcher
              executor = "fork-join-executor"
              throughput = 3
              fork-join-executor {
                parallelism-min = 40
                parallelism-factor = 10
                parallelism-max = 100
              }
            }
       }
    }

我是8核心机器,所以我希望 80 并行线程处于就绪状态   40分钟< 80(8 * 10因子)< 100max 即可。我想看看akka用于最大并行线程的值是多少。 我创建了45个子actor,在我的日志中,我打印了线程id [application-akka.actor.default-dispatcher-xx],并且我看不到超过20个并行运行的线程。

2 个答案:

答案 0 :(得分:0)

假设您有一个ActorSystem实例,您可以检查其配置中设置的值。这就是你如何能够掌握在配置文件中设置的值:

val system = ActorSystem()
val config = system.settings.config.getConfig("akka.actor.default-dispatcher")
config.getString("type")
config.getString("executor")
config.getString("throughput")
config.getInt("fork-join-executor.parallelism-min")
config.getInt("fork-join-executor.parallelism-max")
config.getDouble("fork-join-executor.parallelism-factor")

我希望这会有所帮助。您还可以参考this页面了解有关特定配置设置的更多详细信息。

<强>更新

我在Akka中挖掘了一些,以确切了解它对您的设置使用了什么。您可能已经预料到它会使用ForkJoinPool。用于构建它的并行性由下式给出:

object ThreadPoolConfig {
  ...
  def scaledPoolSize(floor: Int, multiplier: Double, ceiling: Int): Int =
math.min(math.max((Runtime.getRuntime.availableProcessors * multiplier).ceil.toInt, floor), ceiling)
  ...
}

此功能在某些时候用于构建ForkJoinExecutorServiceFactory

new ForkJoinExecutorServiceFactory(
  validate(tf),
  ThreadPoolConfig.scaledPoolSize(
    config.getInt("parallelism-min"),
    config.getDouble("parallelism-factor"),
    config.getInt("parallelism-max")),
  asyncMode)

无论如何,这是用于创建ForkJoinPool的并行性,它实际上是java.lang.ForkJoinPool的一个实例。现在我们要问这个池有多少线程使用?简短的回答是它只会在需要时使用整个容量(在我们的例子中为80个线程)。

为了说明这种情况,我在actor中使用Thread.sleep进行了几次测试。我发现它可以从大约10个线程(如果没有进行睡眠调用)到大约80个线程(如果我称之为睡眠1秒)。测试是在具有8个核心的机器上进行的。

总结一下,您需要检查Akka使用的实现,以确切了解如何使用并行性,这就是我查看ForkJoinPool的原因。除了查看配置文件然后检查特定的实现,我认为你不能不幸地做到:(

我希望这能澄清答案 - 最初我认为你想看看演员系统的调度员是如何配置的。

答案 1 :(得分:0)

为了最大化并行性因素,所有参与者都需要同时处理一些消息。你确定在你的申请中是这种情况吗?

以下面的代码为例

object Test extends App {

  val system = ActorSystem()

  (1 to 80).foreach{ _ =>
    val ref = system.actorOf(Props[Sleeper])
    ref ! "hello"
  }
}

class Sleeper extends Actor {
  override def receive: Receive = {
    case msg =>
      //Thread.sleep(60000)
      println(msg)
  }
}

如果你考虑你的配置和8个核心,你会看到产生少量线程(4,5?)因为消息的处理太快而无法构建一些真正的并行性。

相反,如果让你的演员CPU忙于取消注释讨厌的Thread.sleep,你会发现线程数将达到80.但是,这只会持续1分钟,之后线程会逐渐退出游泳池。

我猜主要的诀窍是:不要认为每个演员都在一个单独的线程上运行。只要一个或多个消息出现在一个演员的邮箱上,调度员就会唤醒它 - 实际上 - 将消息处理任务发送到指定的池。