在Scala和第三方Java库中使用Akka的最佳实践
我需要在Scala/Akka代码中使用。此API为您提供了同步和异步方法。异步的返回。这里有一个关于在Scala中处理Java期货的问题。但就我而言,我有两个选择:在Scala和第三方Java库中使用Akka的最佳实践,java,scala,asynchronous,concurrency,akka,Java,Scala,Asynchronous,Concurrency,Akka,我需要在Scala/Akka代码中使用。此API为您提供了同步和异步方法。异步的返回。这里有一个关于在Scala中处理Java期货的问题。但就我而言,我有两个选择: 将来使用同步API和包装阻塞代码并标记阻塞: Future { blocking { cache.get(key) //synchronous blocking call } } 使用异步JavaAPI,每n毫秒对Java Future进行一次轮询,以检查Future是否完成(如上面链接问题中的一个答案所述)
Future {
blocking {
cache.get(key) //synchronous blocking call
}
}
哪一个更好?我倾向于第一种选择,因为投票会极大地影响响应时间。
blocking{}
block不应该阻止阻塞整个池吗?我总是选择第一个选项。但是我用了一种稍微不同的方式。我不使用阻塞
功能。(实际上我还没有考虑过。)相反,我为将来提供了一个定制的执行上下文,它封装了同步阻塞调用。所以它看起来基本上是这样的:
val ecForBlockingMemcachedStuff = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(100)) // whatever number you think is appropriate
// i create a separate ec for each blocking client/resource/api i use
Future {
cache.get(key) //synchronous blocking call
}(ecForBlockingMemcachedStuff) // or mark the execution context implicit. I like to mention it explicitly.
因此,所有的阻塞调用都将使用专用的执行上下文(=线程池)。因此,它与负责非阻塞内容的主执行上下文分离
Typesafe提供的示例中也解释了这种方法。第4课中有一个关于如何处理阻塞呼叫的视频。Nilanjan Raychaudhuri(希望我拼写正确)对此进行了解释,他是Scala书籍的著名作者
更新:我有一个问题。他解释了阻塞
方法与自定义执行上下文
之间的区别。阻塞
功能只是创建一个特殊的执行上下文
。对于需要多少线程的问题,它提供了一种简单的方法。每当池中所有其他现有线程都忙时,它都会生成一个新线程。因此,它实际上是一个不受控制的执行上下文。它可能会创建大量线程并导致问题,如内存不足错误。因此,使用自定义执行上下文的解决方案实际上更好,因为它使这个问题变得显而易见。Nilanjan还补充说,您需要考虑电路断开的情况,因为这个池被请求过载。
TLDR:是的,阻止通话很糟糕使用自定义/专用ExecutionContext阻止调用。还考虑了电路中断。< /强> < P>对如何处理阻塞调用提供了一些建议:
在某些情况下,进行阻塞操作是不可避免的,即
一个线程在不确定的时间内休眠,等待外部消息
要发生的事件。例如传统的RDBMS驱动程序或消息传递API,
根本原因通常是(网络)I/O发生在
封面。面对这种情况时,您可能会试图将
在将来阻止调用并使用它,但是
策略太简单了:你很可能会发现瓶颈或问题
当应用程序运行时,内存或线程不足
装载
关于“阻塞”的充分解决方案的非详尽清单
“问题”包括以下建议:
- 在参与者(或路由器管理的一组参与者)内执行阻塞调用,确保配置线程池 专用于此目的或尺寸足够大
- 在将来进行阻塞调用,确保在任何时间点(提交无限制的 这种性质的任务数量将耗尽您的内存或线程 限制)
- 在将来执行阻塞调用,为线程池提供适用于 运行应用程序的硬件
- 指定一个线程来管理一组阻塞资源(例如,驱动多个通道的NIO选择器),并在事件发生时进行调度 作为参与者消息出现
是的,我认为这是第三种方法。我只是想知道我是否可以结合使用自定义执行上下文和
阻塞
功能。我在某个地方读到,如果使用自定义执行上下文,则此功能无效,因此在悲观场景中,可以阻止自定义池。