我应该在演员中包装封锁代码与未来吗?

发布于 2025-01-26 05:01:11 字数 580 浏览 3 评论 0原文

我有一个关于阻止演员中呼叫处理的问题。我有一个阻止方法调用blokingProcess()我想在演员中称其为。我是否应该

  1. 将此blokingprocess() future 用专用dispatcher/executionContext将代码>。
  2. 我应该创建主管父母,我将使用专用dispatcher制作儿童演员。该儿童演员将处理阻止呼叫blokingProcess(),而没有任何未来包装器。

注意,我还可以通过将用专用dispatcher/executionContext与No Actor中的Future一起呼叫blokingprocess()。我的程序一次会产生如此多的阻止电话。我不需要回复。

我知道这是非常愚蠢的问题。但是寻找专家的建议。

I have a question regarding of blocking call handling within an actor. I have a blocking method call blokingProcess() I want to call it within an actor. Should I have to

  1. Wrap this blokingProcess() by Future with a dedicated dispatcher/ExecutionContext in an actor then using pipeTo self. Or
  2. I should create a supervisor parent actor under which I will produce child actor with dedicated dispatcher . That child actor will handle the blocking call blokingProcess() without any Future wrapper .

Note I can also call blokingProcess() by wrapping with Future with dedicated dispatcher/ExecutionContext with in no actor. My programme will generate so many blocking calls at a time . I don't need response back.

I know this is very silly question. But looking for experts' suggestions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅紫色的梦幻 2025-02-02 05:01:11

通常,您不想在Actorsystem的主要调度器池的线程上执行长期的螺纹阻挡工作。这是因为它是同一池处理所有您应用程序中的事件(除非专门针对另一个池) - 因此,如果该池被阻塞的线程饱和,则您的应用程序将死亡。

我建议的模式是设置a for IO结合的阻塞工作。然后,您可以通过单个演员之一以两种方式之一:

implicit val ioDispatcher: ExecutionContext = context.system.dispatchers
  .lookup(DispatcherSelector.fromConfig("io-bound-dispatcher"))

val task = Future {
  blocking {
    // blocking work here
  }
}

或以亲子方式使用,在这里,IO结合的调度员用于孩子所做的所有工作:

// in parent
val child = context.spawn(
  childBehavior,
  "child-actor-name",
  DispatcherSelector.fromConfig("io-bound-dispatcher")
)
child ! msg

让孩子在其上进行阻止动作主线程将是IO结合调度员池的线程。

第二种方法的优点是,它使恢复/监督像其他任何演员一样起作用;换句话说,如果您的阻塞操作会引发未被发现的例外,它将起泡监督堆栈,直到处理为止。这可能是您想要的,也可能不是您想要的。

无论哪种情况,最好添加围绕阻止代码的登录,这将使您可以检查操作发生的线程名称。 (警告!akka的默认记录日志默认值线程池上的所有事件;您必须明确要求从MDC中添加日志事件的sourcethread添加到日志输出中。)

注意。设计了所有Akka自己的IO原语(例如HTTP客户端,Kafka消费者等)(通常是通过流API)设计的,以不阻止调度程序线程。因此,除非您非常非常确保他们正在引起线池饥饿(而不仅仅是它的受害者),否则您不应将其移至其他调度员。

You generally don't want to perform long-running thread-blocking work on threads of your ActorSystem's main dispatcher pool. This is because it is that same pool that handles all the events in your application (unless specifically directed to another pool) -- so if that pool gets saturated with blocked threads, your application will deadlock.

The pattern I recommend is to set up a separate dispatcher for IO-bound blocking work. Then you can use in one of two ways, either in a single actor:

implicit val ioDispatcher: ExecutionContext = context.system.dispatchers
  .lookup(DispatcherSelector.fromConfig("io-bound-dispatcher"))

val task = Future {
  blocking {
    // blocking work here
  }
}

or in a parent-child fashion, where the IO-bound dispatcher is used for all work done by the child:

// in parent
val child = context.spawn(
  childBehavior,
  "child-actor-name",
  DispatcherSelector.fromConfig("io-bound-dispatcher")
)
child ! msg

and have the child run the blocking action on its main thread, which will be a thread from the IO-bound dispatcher's pool.

The advantage to the second approach is it makes recovery/supervision work like it does for any other actor; in other words, if your blocking operation throws an uncaught exception, it will bubble up the supervision stack until handled. This may or may not be what you want.

In either case, it's always good to add some logging around the blocking code which will allow you to inspect the thread name that the action is occurring on. (Warning! Akka's default logging logs all events on the default thread pool; you have to explicitly request that the log event's sourceThread from MDC is added to the log output.)

Note that all of Akka's own IO primitives (e.g. HTTP client, Kafka consumer, etc.) are designed (usually by means of the Streams APIs) to not block dispatcher threads. So you should not move these to other dispatchers unless you are very, very sure that it is they that are causing thread-pool starvation (and not merely being the victim of it).

冷夜 2025-02-02 05:01:11

我的答案是

  1. 包裹在Future中,并使用阻止

如果将blockingprocess放入阻止 block中,则调度程序可以为该Future使用专用线程,并避免僵局的风险。

Future{
  blocking{
    blockingProcess()
  }
}

对我来说,使用单独的调度员或儿童演员感觉就像是过度杀伤。

这确实取决于所使用的特定调度程序,因此请参见在这里有关更多详细信息。

My answer is

  1. Wrap in a Future and use blocking

If you put blockingProcess inside a blocking block then the dispatcher can use a dedicated thread for that Future and avoid the risk of deadlock.

Future{
  blocking{
    blockingProcess()
  }
}

Using separate dispatchers or child actors feels like overkill to me.

This does depend on the particular dispatcher being used, so see here for more details.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文