当前位置: 首页 > 知识库问答 >
问题:

Scala和第三方Java库中Akka的最佳实践

马权
2023-03-14

我需要在我的Scala/Akka代码中使用memcached Java API。这个API提供了同步和异步方法。异步的返回java.util.concurrent.Future,这里有一个关于在Scala中处理Java Futures的问题,我如何在Akka Future中包装java.util.concurrent.Future?。然而,在我的情况下,我有两个选择:

>

  • 使用同步API并在未来包装阻塞代码并标记阻塞:

    Future {
      blocking {
        cache.get(key) //synchronous blocking call
      } 
    }
    

    使用异步Java应用编程接口,并在未来上每隔n毫秒Java轮询一次,以检查未来是否完成(如上面链接问题中的一个答案所述)。

    哪一个更好?我倾向于第一个选项,因为轮询会极大地影响响应时间。阻止 { } 块不应该阻止阻塞整个池吗?

  • 共有2个答案

    叶光华
    2023-03-14

    Akka文档提供了一些关于如何处理阻塞调用的建议:

    在某些情况下,不可避免地要执行阻塞操作,即使线程Hibernate一段不确定的时间,等待外部事件发生。示例是旧版 RDBMS 驱动程序或消息传递 API,其根本原因通常是(网络)I/O 是在幕后发生的。当遇到这种情况时,你可能会忍不住把阻塞调用包装在 Future 中,然后改用它,但这种策略太简单了:当应用程序在增加的负载下运行时,你很可能会发现瓶颈或内存或线程不足。

    “阻塞问题”的适当解决方案的非详尽清单包括以下建议:

    在将来进行阻塞调用,确保在任何时间点上这种调用的数量上限(提交无限数量的这种性质的任务将耗尽您的内存或线程限制)。

    在将来进行阻塞调用,为线程池提供一个适合应用程序运行的硬件的线程数量上限。

    专用于单个线程来管理一组阻塞资源(例如,驱动多个通道的NIO选择器)并在事件作为参与者消息发生时分派事件。

    第一种可能性特别适合于本质上是单线程的资源,比如传统上一次只能执行一个未完成的查询并使用内部同步来确保这一点的数据库句柄。常见的模式是为N个参与者创建一个路由器,每个参与者包装一个DB连接,并处理发送到路由器的查询。然后,数字N必须调整为最大吞吐量,这将根据在什么硬件上部署哪个DBMS而变化。

    茹展鹏
    2023-03-14

    我总是选择第一个选项。但我以稍微不同的方式做到这一点。我不使用阻止功能。(实际上我还没有想过。相反,我正在为Future提供一个自定义执行上下文,用于包装同步阻塞调用。所以它基本上看起来像这样:

    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.
    

    因此,所有阻塞调用都将使用专用的执行上下文 (= Threadpool)。因此,它与负责非阻塞内容的主执行上下文分离。

    Typesafe 提供的 Play/Akka 在线培训视频也解释了这种方法。第 4 课中有一个关于如何处理阻塞呼叫的视频。它由Nilanjan Raychaudhuri(希望我拼写正确)解释,他是Scala书籍的着名作者。

    更新:我在Twitter上与Nilanjan进行了讨论。他解释了使用阻塞的方法和自定义执行上下文的方法之间的区别。阻塞功能只是创建一个特殊的执行上下文。它为您需要多少线程的问题提供了一种朴素的方法。每次当池中的所有其他现有线程都处于繁忙状态时,它都会生成一个新线程。所以它实际上是一个不受控制的执行文本。它可能会创建大量线程并导致内存不足错误等问题。因此,具有自定义执行上下文的解决方案实际上更好,因为它使此问题变得明显。Nilanjan还补充说,如果此池的请求过载,您需要考虑断路。

    TLDR:是的,阻止呼叫很糟糕。使用自定义/专用的执行上下文来阻止调用。还要考虑断路。

     类似资料:
    • 问题内容: 我需要在Scala / Akka代码中使用memcached Java API 。该API为您提供同步和异步方法。异步的返回java.util.concurrent.Future。这里有一个关于在Scala中处理JavaFutures的问题,如何在AkkaFuture中包装java.util.concurrent.Future?。但是,就我而言,我有两种选择: 使用同步API并在以后包

    • 首先,我是一个OSGI新手:-) 谢了!

    • 将源代码和资源文件复制到我们自己的项目中。我们需要更改很多代码(包名、xml中的名称等) 如果提供了jar文件,我只需为我的项目创建libs文件夹并复制其中的jar文件。并在模块设置的依赖项中添加jar文件。但不幸的是,我收到了很多错误消息,比如“gradle:Package com.google.gson doesn't exist”。 在现有的android studio项目中添加第三方源代码

    • 这是最好的方法吗?你们会推荐哪种方法?为什么?在这个用例的范围内有几个最好的实践示例将是很棒的! 提前致谢:)

    • 我已经下载了代数鸟,我想使用这个库在Scala解释器中试用一些东西。我如何实现这一点?

    • 是否可以将恶意软件隐藏到Java库中?我正在学习java,我也读过很多关于第三方库的用法,但是它们会包含恶意软件吗?我有点担心,因为我不想以后被感染。