Quasar和Akka –比较

actor模型是用于容错和高度可扩展系统的设计模式。 角色是独立的工作程序模块,仅通过消息传递与其他角色进行通信,可以与其他角色隔离而失败,但是可以监视其他角色的故障并在发生这种情况时采取一些恢复措施。 参与者是简单,孤立但又协调的并发工作者。

基于演员的设计带来许多好处:

  • 自适应行为 :仅通过消息队列进行交互会使参与者松散耦合,并允许他们:
    • 隔离故障 :邮箱将消息队列解耦 ,使参与者可以在不中断服务的情况下重新启动。
  • 最大并发容量
    • Actor在内存消耗和管理开销方面都非常轻巧 ,因此可以在一个盒子中生成甚至数百万个。
  • 低复杂度
    • 每个参与者都可以通过更改其私有状态来实现有状态行为,而不必担心并发修改。

凭借Erlang ,演员模型得到了广泛认可,并成功实现了关键生产系统中的目标。

这是针对JVM的两个参与者库的比较回顾:我们自己的Quasar和Typesafe的Akka

类星体

Quasar是一个用于简单,轻量级JVM并发的开源库,该库在JVM上实现了真正的轻量级线程(AKA光纤)。 Quasar光纤的行为与普通Java线程一样,除了它们几乎没有内存和任务切换开销之外,因此您可以在单个JVM中轻松产生数十万甚至上百万的光纤。 Quasar还提供了以Go语言提供的模式为模型的光纤间通信通道,并带有通道选择器。 它还包含actor模型的完整实现,该模型以Erlang为蓝本。

尽管本文主要涉及Quasar在Actor模型的实现上建立的,该模型建立在Quasar光纤之上,但请记住,您可以在没有actor的情况下使用Quasar。

类星体演员实现了上面概述的完整的演员范式,其中一些适用于Java 7,Java 8, Clojure和Kotlin 。 Quasar当前不支持Scala。

由于Quasar光纤的工作原理与线程非常相似,因此可以轻松地集成现有库,因此可以在不更改代码或进行最少代码更改的情况下使用当前工具和库,同时充分利用轻量级线程的效率。 这样可以保留现有代码,并避免API锁定。 Comsat项目利用Quasar的集成框架,以最少的代码为光纤提供了几个流行的标准API的端口移植(它还引入了Web Actors ,这是一个基于actor的新的HTTP,WebSocket和SSE的基于Web的API)。

Quasar光纤是通过创建和安排连续任务来实现的,并且由于JVM还不支持本机连续,因此Quasar通过选择性字节码检测来实现它们:当前可以阻塞光纤的方法需要通过注释进行显式标记,以便Quasar可以插入继续悬挂和恢复挂钩。 但是,可以使用实验性的自动Clojure工具,并且自动工具也将扩展到其他JVM语言。 可以作为附加的构建步骤或在运行时执行检测(通过JVM代理或大多数常见Servlet容器的类加载器)。

阿卡

Akka是用Scala编写的actor框架,除了Scala之外,它还支持Java 7,Java 8(从2.3.10开始的实验)。 它提供基于异步,基于回调的Actor DSL,而不是基于Erlang的基于光纤的Actor系统。 Akka不提供轻量级线程,而是依靠JVM线程来调度参与者。 Akka不是一个库,而是一个提供全方位服务的框架,涵盖了从配置和部署到测试的所有内容。

无阻塞

Akka和Quasar actor之间的主要区别是Akka使用了异步的非阻塞API,而Quasar –例如Erlang,Go,Clojure的core.async –使用了阻塞API:在Akka中,actor 实现receive方法,即当actor收到消息时触发的回调,而在Quasar中,actor 调用 receive方法,该方法一直阻塞,直到收到消息为止。 从理论上讲,异步和直接(或阻塞)样式是双重的和等效的,因为它们可以相互转换 ,但是在实践中,实现的细节对性能和可伸缩性以及选择哪种样式有很大影响。编程语言可以使一种方法比另一种方法容易。

选择基于回调的异步方法的原因是,阻塞普通的OS线程会带来大量开销(就像许多线程的存在一样),而使用非阻塞API可以避免这种情况。 但是,由于Quasar(与Erlang和Go一样)具有真正的轻量级线程,因此阻塞几乎没有开销。

在语言方面,虽然Scala为monad提供了语法支持,这使处理异步代码变得更加简单,但是在对monad没有良好语法支持的语言(例如Java)中,阻塞方法要简单得多。 阻塞代码的优点不仅在于更简单,更具可读性和可维护性的 Java代码,还在于更加熟悉和兼容的代码,可以集成其他标准Java API。

API比较

Quasar Java API支持Java 7和8。Clojure支持是Pulsar的一部分, Pulsar是Quasar周围的一个很薄的包装层,非常习惯,并且提供了与Erlang相似的actor API。 Kotlin支持是最新添加的功能。 Kotlin是一种非常有前途的针对JVM和JavaScript的静态类型混合编程语言,由领先的供应商JetBrains的开发工具设计和构建,使其高效且可集成。 尽管Kotlin使使用现有Java API的效果比Java本身更有效,更安全,更轻松,更愉快。

Quasar还提供了一个集成工具箱,该工具箱可以添加对其他JVM语言的支持。

Akka在设计时主要考虑了Scala,但一段时间以来它一直在提供附加的Java API。

以下是Quasar和Akka Java API之间的比较。 尽管还不够详尽,但它涵盖了关键的差异。 这是一个简短的摘要:

功能表

演员定义

Quasar (Kotlin和Java)参与者实现了doRun方法(或Clojure中的函数),就像在Erlang中一样,该方法可以使用任意语言控制流构造,并且只要开发人员认为合适就可以阻塞操作。 通常它将至少使用receive (正常或选择性)和send

class MyActor extends BasicActor<String, MyActorResult> {private final Logger log = LoggerFactory.getLogger(MyActor.class);@Suspendable@Overrideprotected MyActorResult doRun() throws InterruptedException, SuspendExecution {// ...Arbitrary code here...final String msg = receive(m -> {if ("test".equals(m)) return "testMsg";else return null; // Defer});// ...Arbitrary code here...return new MyActorResult();}
}

由Pulsar提供的Clojure API更加简洁:

(def log (LoggerFactory/getLogger (class *ns*)))(spawn#(; ...Arbitrary code here...(receive                                ; Single, fiber-blocking, selective receive"test" (do (. log info "received test") "testMsg")) ; Other messages will stay in the mailbox; ...Arbitrary code here...))

类星体参与者(如Erlang进程)使用阻塞接收,并被允许执行阻塞IO(尽管阻塞IO操作最终不会阻塞OS线程,而是阻塞光纤,这使它们具有很高的可伸缩性)。

Akka actor被实现为receive 事件的回调,并且不允许阻塞:

public class MyUntypedActor extends UntypedActor {LoggingAdapter log = Logging.getLogger(getContext().system(), this);// "receive" must be toplevelpublic void onReceive(Object message) throws Exception {if ("test".equals(message))log.info("received test");elselog.info("received unknown message")}
}

演员生命周期和监督层次

类星体 actor的创建和启动就像在光纤上一样容易:

ActorRef myActor = new MyActor().spawn();

尽管Quasar和Akka都支持监视(也可以监视 )其他参与者的故障,但Akka强制将参与者添加到适当的监督层次结构中,因此必须始终通过指定参与者的类和适当的构造函数参数的配方来实例化参与者。 顶级演员必须由演员系统生成,子演员必须由父母的上下文生成:

ActorRef myActor = system.actorOf(Props.create(MyActor.class), "myactor");

监督是一种分层的故障管理模式,提供了故障隔离的良好实践:当角色终止时,主管将根据其监督策略进行操作。 受监督的儿童演员可能因永久性故障,暂时性故障或仅完成工作而终止。 终止时,主管通常可以选择使自己失败( 升级 ),仅重新启动失败的孩子或重新启动所有孩子。

在Quasar中,就像在Erlang中一样,监督是可选的,而supervisor只是一个预先构建的(尽管是可配置的)actor,它通过内部使用原始actor监视操作(监视和链接)来提供监督。 当使用主管时,Quasar也需要指定创建演员的方法(以及其他信息,例如主管在放弃之前应尝试多少次重试等):

ChildSpec actorSpec = new ChildSpec("myactor", TRANSIENT, 1, 1, MILLISECONDS, 100, MyActor::new);
Supervisor mySupervisor = new SupervisorActor(ALL_FOR_ONE, actorSpec).spawn();

Quasar还允许通过可Actor.reinstantiate方法来监督和重新启动预先构建的本地actor实例,因此它可以与任何依赖项引擎一起使用。

Akka提供了几种关闭参与者的方法。 Quasar和Erlang一样,只是鼓励一条简单的消息来表示关闭请求(尽管这种通用机制已经是所有行为的一部分–参见下文); 通过中断演员的基础线 (线或纤维),可以突然终止。

行为举止

Quasar遵循Erlang OTP库的示例,为常见的actor类型(称为behaviors)提供可配置的actor模板。 行为都实现通用,有用的消息传递模式,但是在Quasar中,它们还为参与者的引用添加了便捷方法。 Quasar的行为均以OTP建模:

  • EventSourceActor (模仿Erlang的gen_event建模)可以动态注册和取消注册处理程序,这些处理程序将仅对收到的消息作出反应。 如果您认为这种特定类型的Quasar actor与仅反应的异步Akka actor非常接近,那么您的方向正确。
  • ServerActor (模仿Erlang的gen_server建模)对公开请求-响应API的服务进行建模。
  • ProxyServerActor允许编写基于接口的服务器:它通过传递任何接口实现而构建,并且将生成ActorRef ,该ActorRef将代理接口并将与接口方法相对应的消息发送到底层服务器actor。 当然,这只是一个用例,但我认为当将传统API移植到Quasar actor时,该行为actor会有所帮助。
  • 在即将到来的Quasar 0.7.0(以Erlang的gen_fsm建模)中添加了FiniteStateMachineActor ,可以轻松地将actor编写为显式的有限状态机。

Akka不包括这种预建的actor模板。 相反,各种常见行为内置于标准API。

演员系统

Akka可以作为独立部署的容器或库运行; 它是通过引用多个参与者系统的配置文件来设置的,每个参与者系统由一个主管监督。 该配置包括日志记录,调度(AKA作为调度),网络,消息序列化和平衡(AKA路由)。 还提供了合理的默认值,因此配置是可选的。

在Akka中,actor系统是重量级的对象,它对应于逻辑应用程序。 Quasar是一个库,而不是一个框架,它根本没有参与者系统的概念,因为它不需要包含整个应用程序。 当然,各种特定的配置是可能的:

  • 光纤的默认调度程序是fork-join(工作窃取),但甚至可以为每个光纤选择它。 参与者只是继承了用于其上运行的链的调度机制,这意味着他们自己不需要调度/调度设置。
  • 监督层次结构是可选的,因此不需要“根”主管。
  • 可以使用任何日志记录机制,但是(可选)行为为此使用“标准”日志记录API SLF4J 。
  • Quasar提供了现成的Galaxy群集中的网络演员和演员迁移功能,但可以提供更多支持。 群集功能是在群集提供程序的配置(例如Galaxy)中设置的,而不是在Quasar本身中设置的。
  • 类星体与部署无关。 对于适用于所有JVM应用程序(也适用于采用Quasar的应用程序)的酷部署解决方案,建议您看一下Capsule 。

内部参与者API

Quasar演员的默认内部API仅包括以下内容:

  • receive / tryReceive方法和一个可重写的filterMessage用于在接收到消息之前将其丢弃。
  • 对参与者的外部,不透明引用。
  • 基本的actor监视构造linkwatch和可handleLifecycleMessage

更多功能,例如默认情况下嵌入的发件人引用,日志记录,终止请求处理,请求服务,事件处理和监督,可以通过扩展预建行为来获得或由您添加。 而且,由于有了Quasar光纤,发送和接收操作可以同时被阻塞并且效率很高,因此不需要异步的,返回Future send变量,例如Akka的ask

始终为所有参与者启用Akka功能(例如监视和监督),因此内部API广泛:

  • receive方法。
  • 对参与者的外部,不透明引用。
  • 对最后一个消息发件人的引用(如果有)。
  • 可覆盖的生命周期方法。
  • 使用的主管策略。
  • 具有附加功能的context属性,例如:
    • 创建受监管孩子的工厂方法。

Akka还提供了一个可选的Stash特性,可以管理第二条已收到但应延迟处理的消息队列。 相反,Quasar与Erlang一样,允许选择性接收,因此它不需要开发人员仅出于延迟消息处理的目的来管理其他消息队列。

热升级

Quasar通过在JMX或指定的“模块”目录中加载新类,从而允许在运行时完全自动地升级actor。 Quasar还允许通过@OnUpgrade注释的方法以受控方式升级@OnUpgrade

换一个演员的部分功能用一个新的运行时虽然阿卡支持become方法,但提供了一流的重新定义不支持,所以无论是演员的行为必须以字节码已经存在于正在运行的JVM或新代码来替换必须通过一些其他的加载工具。

网络,远程处理,可靠性和集群

Quasar作为Galaxy上群集集群的一部分,开箱即用地支持远程参与者,但是可以添加更多的远程处理和群集提供程序。 Akka提供了类似的功能以及预先构建的功能,可以直接在远程节点上生成角色,并在单独节点上的角色之间进行负载平衡消息。

Quasar还通过实验支持actor 迁移 -暂停正在运行的actor并将其恢复到另一台计算机上的能力。

邮箱持久性

Akka包括一个基于其基础事件源引擎的实验性邮箱持久性支持,并且要求actor扩展PersistentActor特性并为正常行为和恢复提供两个单独的事件处理程序,以及显式调用persist

Quasar目前不支持actor邮箱持久性。

积分

Quasar不会强迫开发人员使用actor系统的所有功能,也不会完全使用actor。 实际上,Quasar为第三方技术提供了易于使用的集成框架,这些框架具有异步,基于未来的API或阻塞API ,因此它们可以与轻量级线程(“光纤”)一起使用,而不能与常规的重量级线程一起使用。 Quasar允许您自由地混合actor和非actor代码,或使用actor代码中的任何集成库,而无需专门的API。

Comsat使用此框架来集成标准和流行的Java和Clojure技术:

  • Dropwizard
  • 泽西岛 JAX-RS (客户端和服务器)
  • Spring Boot (Web控制器)
  • OkHttp
  • HTTP客户端
  • 翻新
  • 小程序
  • Clojure戒指

Comsat还包括Web Actors ,这是一个新的actor API,用于处理HTTP,WebSocket和SSE交换。

目前, Akka项目提供:

  • Apache Camel消息传递集成。
  • 基于HTTP actor的API( Spray )。
  • 基于ZeroMQ actor的API。
  • 基于TCP参与者的API。
  • 基于UDP actor的API。
  • 基于文件IO actor的API。

Akka与不基于消息传递的系统的集成必然是新的参与者API。

测试中

Quasar不包含专用的测试工具包,因为它是一个支持临时参与者的阻塞框架,临时参与者的链可以在终止时产生价值,因此任何常规测试工具(如JUnit)都可以与常规多线程测试实践一起使用。

Akka是一个异步框架,因此它必须以阻止单角色测试调用( TestActorRefTestFSMRef )的形式提供专用的API。 它还提供了启用了ScalaTest断言的特殊参与者,以对整个参与者子系统( TestKit mixin或TestProbe )执行外部集成测试。 支持定时断言,监督测试,消息交换限制,消息交换和故障跟踪。

系统监控与管理

Quasar通过标准JMX MBean公开了丰富的actor监视数据(邮箱,堆栈跟踪),可以监视启用JMX的工具(例如JDK的免费提供的JVisualVM和JConsole),或者使用REST API使用Jolokia 。 此外,Quasar还提供工具来微调仪器并记录详细的光纤执行轨迹。

可以通过专有软件(Typesafe Console)监视和管理Akka应用程序,该软件需要生产系统的商业许可。

新的Relic和App Dynamics支持Akka和Quasar(通过JMX)。

完整应用比较:类比股票和反应型股票

要了解Akka和Quasar之间的异同,没有比查看使用两者编写的相同应用程序的代码更好的方法了。 Quasar Stocks是Reactive Stocks Play / Akka激活器模板的Java端口,用于Quasar参与者和Comsat Web参与者。

在385行代码中,纯Java Quasar应用程序几乎像半Scala Typesafe应用程序(285个位置)一样紧凑,考虑到actor和Web Actor只能做一件事,这特别好:一切都是一致的。与JSON库无关,因此您不必被迫仅使用一个Web框架并接受其有关Web开发问题的意见。

而且我仍然认为Quasar一个人比较容易理解,因为它是一种古老的Java命令式样式,仅在效率更高的轻量级线程实现上运行:没有声明性/功能性/ monadic / async强制您解决JVM问题线程的足迹很大。

例如,可以将Typesafe版本中基于“未来情绪”的Web服务替换为同等高效且完全传统的JAX-RS Jersey版本,仅使用光纤阻塞而不是线程阻塞。 因此,与其使用异步操作Future和专用的非标准DSL来组成它们,就像在Typesafe版本中那样:

object StockSentiment extends Controller {case class Tweet(text: String)implicit val tweetReads = Json.reads[Tweet]def getTextSentiment(text: String): Future[WSResponse] =WS.url(Play.current.configuration.getString("sentiment.url").get) post Map("text" -> Seq(text))def getAverageSentiment(responses: Seq[WSResponse], label: String): Double = responses.map { response =>(response.json \\ label).head.as[Double]}.sum / responses.length.max(1) // avoid division by zerodef loadSentimentFromTweets(json: JsValue): Seq[Future[WSResponse]] =(json \ "statuses").as[Seq[Tweet]] map (tweet => getTextSentiment(tweet.text))def getTweets(symbol:String): Future[WSResponse] = {WS.url(Play.current.configuration.getString("tweet.url").get.format(symbol)).get.withFilter { response =>response.status == OK}}def sentimentJson(sentiments: Seq[WSResponse]) = {val neg = getAverageSentiment(sentiments, "neg")val neutral = getAverageSentiment(sentiments, "neutral")val pos = getAverageSentiment(sentiments, "pos")val response = Json.obj("probability" -> Json.obj("neg" -> neg,"neutral" -> neutral,"pos" -> pos))val classification =if (neutral > 0.5)"neutral"else if (neg > pos)"neg"else"pos"response + ("label" -> JsString(classification))}def get(symbol: String): Action[AnyContent] = Action.async {val futureStockSentiments: Future[Result] = for {tweets <- getTweets(symbol) // get tweets that contain the stock symbolfutureSentiments = loadSentimentFromTweets(tweets.json) // queue web requests each tweets' sentimentssentiments <- Future.sequence(futureSentiments) // when the sentiment responses arrive, set them} yield Ok(sentimentJson(sentiments))futureStockSentiments.recover {case nsee: NoSuchElementException =>InternalServerError(Json.obj("error" -> JsString("Could not fetch the tweets")))}}
}

可以编写一个完全标准的,熟悉的JAX-RS服务,唯一的区别是附加的@Suspendable注释和生成纤维,而不是用于并行操作的线程:

@Singleton
@Path("/")
public class Sentiment {final CloseableHttpClient client = FiberHttpClientBuilder.create(Runtime.getRuntime().availableProcessors()).setMaxConnPerRoute(1000).setMaxConnTotal(1000000).build();@GET@Path("{sym}")@Produces(MediaType.APPLICATION_JSON)@Suspendablepublic JsonNode get(@PathParam("sym") String sym) throws IOException, ExecutionException, InterruptedException {List<Fiber<JsonNode>> agents = new ArrayList<>();List<JsonNode> sentiments = new ArrayList<>();for (JsonNode t : getTweets(sym).get("statuses"))agents.add(sentimentRetriever(t.get("text").asText())); // spawn worker fibersfor (Fiber<JsonNode> f : agents) // join fiberssentiments.add(f.get());return sentimentJson(sentiments);}private JsonNode sentimentJson(List<JsonNode> sentiments) {Double neg = getAverageSentiment(sentiments, "neg");Double neutral = getAverageSentiment(sentiments, "neutral");Double pos = getAverageSentiment(sentiments, "pos");ObjectNode ret = Application.Conf.mapper.createObjectNode();ObjectNode prob = Application.Conf.mapper.createObjectNode();ret.put("probability", prob);prob.put("neg", neg);prob.put("neutral", neutral);prob.put("pos", pos);String c;if (neutral > 0.5)c = "neutral";else if (neg > pos)c = "neg";elsec = "pos";ret.put("label", c);return ret;}private Double getAverageSentiment(List<JsonNode> sentiments, String label) {Double sum = 0.0;final int size = sentiments.size();for (JsonNode s : sentiments)sum += s.get("probability").get(label).asDouble();return sum / (size > 0 ? size : 1);}private Fiber<JsonNode> sentimentRetriever(String text) throws IOException {return new Fiber<> (() -> {HttpPost req = new HttpPost(Application.Conf.sentimentUrl);List<NameValuePair> urlParameters = new ArrayList<>();urlParameters.add(new BasicNameValuePair("text", text));req.setEntity(new UrlEncodedFormEntity(urlParameters));return Application.Conf.mapper.readTree(EntityUtils.toString(client.execute(req).getEntity()));}).start();}@Suspendableprivate JsonNode getTweets(String sym) throws IOException {return Application.Conf.mapper.readTree (EntityUtils.toString(client.execute(new HttpGet(Application.Conf.tweetUrl.replace(":sym:", sym))).getEntity()));}
}

阻塞样式还有另一个好处:Quasar API 更小更简单 。 例如,完全不需要Akka对计划消息的特定支持,因为在Quasar中,演员主体可以使用常规的控制流构造。 所以代替:

// Fetch the latest stock value every 75ms
val stockTick = context.system.scheduler.schedule(Duration.Zero, 75.millis, self, FetchLatest)

在消息处理循环中定期进行光纤阻塞定时接收已绰绰有余:

for(;;) {Object cmd = receive(75, TimeUnit.MILLISECONDS);if (cmd != null) {// ...} else self().send(new FetchLatest());// ...
}

此外,默认情况下,Quasar Web Actor会自动将新的actor分配给新的HTTP会话或WebSocket连接,因此Quasar完全不需要Typesafe版本的基于回调的应用程序控制器 ,因为一切都由actor直接处理,它将浏览器(或移动客户端)简单地看作另一个参与者,它可以监视以监视客户端的终止。

关于应用程序的Typesafe 教程提到了几种类型的设计模式:

  • 响应式推送基本上意味着将线程有效地分配给参与者以处理WebSocket交换。 通过使用Quasar的基于光纤的actor,可以有效地完成此任务,而不会限制常规控制流构造的使用。
  • 反应性请求反应性组合基本上是指使用异步构造(例如Future的单子组合,以实现Web服务中有效的线程使用。 在光纤上运行时,这种复杂性是完全没有必要的:您可以使用常规的,直接的阻塞调用和控制流,并且光纤调度程序可以为您处理线程以达到相同的效果和性能。
  • 反应式UI基本上已经被复制到Quasar Stocks中。

最后,Web Actor是100%Servlet兼容的,因此,如果您不想运行非标准嵌入式服务器,则无需运行。 相反,Play必须独立运行2

性能比较

环形测试JMH基准测试套件基于Fiber-test ,并从Fiber-test派生而来,比较了基于Akka,Quasar Actors,Java Threads和Quasar光纤(带有或不带有不同类型的通道)的几种消息传递实现。

基准将工人参与者安排成一个环形,并执行消息传递循环。 变量是:

  • 工作人员人数(默认= 503)
  • 循环的长度(默认= 1E + 06消息交换)
  • 响铃次数(默认= 1)
  • 在每次消息交换及其参数之前执行的业务逻辑(默认=无)。

所有测试均在2008年底的MacBook Pro铝制版,8GB RAM,Mint Linux(Linux 3.13.0-49通用)下使用Core 2 Duo P8600 2.4Ghz,JDK 1.8.0_45-b14进行了积极的优化和分层编译的情况下进行。已启用。 使用的JMH版本是1.8,带有5个fork,5个热身迭代和10个迭代。

首先让我们看一下带有默认参数的内存占用量:

性能表

与光纤和Quasar actor相比,Akka具有最高的堆使用率,最高的GC事件数和最高的GC总时间,因此Quasar总体上具有较低的内存占用量。

关于速度,首先要注意的是,改变工人角色的数量,甚至达到数百万,都不会改变Quasar和Akka的单环性能数据:这证实了角色(和光纤)确实非常轻巧。

然后进行了两组测量:第一个测量具有固定数量的1E + 04消息交换和变化的业务工作量,显示Quasar的启动速度稍快,但是随着工作量开始占主导地位,Akka和Quasar的执行情况非常相似:

性能增加负载图

在没有工作负载和数量不定的消息交换的情况下,我们测量的是纯框架开销 。 Quasar再次启动得更快,但是Akka领先,Quasar的额外开销达到并稳定在Akka的80%左右:

性能提高msgs图表

由于缺少JVM中的本机连续性,JMH perfasm分析回合突出显示了Quasar中与用户堆栈管理相关的真正轻量级线程的额外成本。 Akka不提供真正的轻量级线程,因此没有开销。

当然, 任何开销(无论多么小)都比没有开销要大得多。 要了解实际开销是否重大,我们必须将其与实际工作负载进行比较。 每条消息的业务工作量相当于对224个元素的int数组进行排序,或者等效地,在1700字节的纯alpha文本上匹配预编译的仅6个数字的正则表达式(失败)匹配项(在3到4微秒上)基准系统),Quasar比Akka 慢1%

绩效表

这意味着在最坏的情况下, 对于平均每个消息交换在1700字节文本上平均至少执行6字符正则表达式匹配的应用程序,性能差异将小于1% 。 由于大多数应用程序的功能远不止这些,因此实际上,您可以获得Quasar光纤和actor可以提供的与Akka 3 相同性能的大量额外编程功能

结论

Quasar是Java,Clojure和Kotlin的快速,精简和实用的并发库,提供了真正的轻量级线程和许多成熟的并发范例,包括与Erlang几乎相同的actor模型的实现。 Quasar的集成,采用和退出成本也很低。 它的功能集中,并且在提供日志记录和监视等其他功能的地方,它使用标准API(SLF4J,JMX等)。

Akka是一个应用程序框架,与Play等其他Typesafe框架一样,它是一个全面的选择,涵盖了整个应用程序,引入了自己的丰富API(甚至用于日志记录),测试工具,监视和部署。

Akka –甚至是其Java API –受Scala的影响很大,并且Java开发人员可能会觉得陌生。 无论您是编写Java,Clojure还是Kotlin,类星体演员都非常熟悉和习惯。

Akka的API是基于回调的。 Quasar提供了真正的光纤(如Erlang或Go),因此阻塞是免费的,并且Quasar的actor API更简单,更熟悉并且与其他代码兼容。 像基于Erlang那样,基于阻塞和基于光纤允许使用很少的基本概念,而Akka引入了许多不熟悉和多余的概念。 例如,要解决缺少简单的阻止选择性接收(由Erlang和Quasar提供)的问题,Akka必须引入消息存储。 其他概念(如单子期货)与业务逻辑或参与者模型无关,但纯粹是偶然的复杂性。

如果发生以下情况,Akka无疑是必经之路:

  • 您已经接受了Scala,并喜欢它的编程风格。
  • 您不用担心押在框架上并坚持下去,也不必为选择退出而付出潜在的高昂重新设计/重写价格。
  • 您准备为生产监视付费,或者愿意编写自己的监视解决方案。

否则,我建议您尝试一下Quasar:它可用于生产,轻量级,快速,基于标准,易于集成,完全免费且开源,并且比Akka的异步参与者提供的功能更多,且复杂度更低。

  1. 有几种参与者系统不支持选择性接收,但是Erlang可以。 乌尔夫·维格(Ulf Wiger)的演讲“偶然复杂性导致的死亡”显示了如何使用选择性接收避免实现完整,复杂且容易出错的转换矩阵。 在另一场演讲中 ,Wiger将非选择性(FIFO)接收与俄罗斯方块游戏进行了比较,在俄罗斯方块游戏中,您必须在拼图中放入每个拼图,而选择性接收则将问题变成了拼图游戏,您可以在其中寻找一块拼图你知道会适合的。
  2. 除非您使用具有某些限制的第三方插件 。
  3. 2048字节以上的Quasar变得比Akka更快,但到目前为止的原因尚不清楚,这可能与更有利的内联有关。

翻译自: https://www.javacodegeeks.com/2015/05/quasar-and-akka-a-comparison.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360281.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dlgdata.cpp错误提示 解决方案

1、在测试编写继承CStatic类组件时候&#xff0c;发现在调用调试过程中弹出一个错误&#xff0c;点忽略还可以继续运行。如下图&#xff1a; 2、dlgdata.cpp此文件是VS安装目录\Microsoft Visual Studio .NET 2003\Vc7\atlmfc\src\mfc中的文件&#xff0c;而出现此错误一般是所…

mysql主从复制时间配置_MySQL主从复制配置

环境CentOS 7.5Docker 1.13.1MySQL 8.0.16基于以上环境启动三个mysql容器&#xff0c;一个为master&#xff0c;二个为slavemaster和slave使用的mysql版本是完全一致的&#xff0c;未测试不同版本的mysql配置master编辑配置文件编辑master的配置文件my.cnf$ vim /usr/mysql/con…

C语言操作符优先级

转自&#xff1a;http://www.cnblogs.com/xiehy/archive/2010/02/04/1663825.html 优先级 运算符 含 义 要求运算 对象的个数 结合方向 1 () [] -> . 圆括号 下标运算符 指向结构体成员运算符 结构体成员运算符 自左至右 2 ! 逻辑非运算符 1 (单目运算符)…

Win7下硬盘安装Redhat双系统

Win7下硬盘安装Redhat Linux 形成双系统过程详解 需要软件 EasyBCD2.0 和 linux ISO 系统镜像 RedHat linux下载地址&#xff1a;http://www.linuxidc.com/Linux/2013-01/78017.htm 安装前准备工作: 1 一个 Windows 盘 D E F 任选其一都可以&#xff0c;将其格式化为FAT32 格式…

java rmi漏洞工具_学生会私房菜【20200924】Weblogic WLS核心组件反序列化命令执行突破(CVE20182628)漏洞复现...

学生会私房菜学生会私房菜是通过学生会信箱收集同学们的来稿&#xff0c;挑选其中的优质文档&#xff0c;不定期进行文档推送的主题。本期文档内容为&#xff1a;Weblogic WLS核心组件反序列化命令执行突破(CVE-2018-2628)漏洞复现》作者介绍&#xff1a;ChowChow&#xff0c;一…

ASP.NET伪静态-无法读取配置文件,因为它超过了最大文件大小的解决办法

一直都在使用微软URLRewriter&#xff0c;具体的使用方法我就不多说了&#xff0c;网上文章很多。 但最近遇到一个问题&#xff0c;就是当web.config文件里面设置伪静态规则过多&#xff0c;大于2M的时候&#xff0c;就报错&#xff1a;无法读取配置文件&#xff0c;因为它超过…

java定义list_我的Java Web之路59 - Java中的泛型

本系列文章旨在记录和总结自己在Java Web开发之路上的知识点、经验、问题和思考&#xff0c;希望能帮助更多(Java)码农和想成为(Java)码农的人。目录介绍再谈Java中的类型为什么需要泛型&#xff1f;Java中的泛型泛型类型泛型方法总结介绍还记得我在这篇文章(我的Java Web之路3…

通过更改透明度使图片为透明

使用AlphaBlend函数 函数功能 该函数用来显示具有指定透明度的图像。函数原型 AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int hHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunc…

(转)CocoaPods:管理Objective-c 程序中各种第三方开源库关联

在我们的iOS程序中&#xff0c;经常会用到多个第三方的开源库&#xff0c;通常做法是去下载最新版本的开源库&#xff0c;然后拖拽到工程中。 但是&#xff0c;第三方开源库的数量一旦比较多&#xff0c;版本的管理就非常的麻烦。有没有什么办法可以简化对第三方库的管理呢&…

为什么子进程每次执行顺序不一样_看完这篇还不懂Redis的RDB持久化,你来打我...

推荐观看&#xff1a;Redis缓存穿透的终极解决方案&#xff0c;手写布隆过滤器_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.comP8架构师串讲&#xff1a;Redis&#xff0c;zookeeper&#xff0c;kafka&#xff0c;Nginx等技术_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​w…

Spring XD用于数据提取

Spring XD是一个功能强大的工具&#xff0c;它是一组可安装的Spring Boot服务&#xff0c;可以独立运行&#xff0c;在YARN或EC2之上运行。 Spring XD还包括一个管理UI网站和一个用于作业和流管理的命令行工具。 Spring XD是一组功能强大的服务&#xff0c;可与各种数据源一起使…

JDK 9 REPL:入门

会议是聚会Java名人的好地方。 Devoxx France是与Java语言架构师&#xff0c;前同事和老朋友Brian Goetz&#xff08; briangoetz &#xff09;见面的一个机会。 我们谈论了JDK 9&#xff0c;而他全都热衷于REPL。 他提到&#xff0c;尽管Java SE 9中有很多重要功能 &#xff0…

sinaapp mysql连接_手把手教你在新浪云上免费部署自己的网站--连接数据库

看完之后&#xff0c;默认你知道怎么将代码上传到新浪云SAE&#xff0c;并且能够成功运行&#xff0c;连接数据库之前&#xff0c;你必须先创建有一个应用。现在我创建一个名称为sampleone的应用&#xff0c;如下图点击左侧的代码管理&#xff0c;选在右侧创建一个版本然后就会…

7 centos 查看程序文件数量_解析CentOS 7中系统文件与目录管理

LINUXLinux操作系统解析CentOS 7中系统文件与目录管理Linux目录结构Linux目录结构是树形的目录结构根目录所有分区、目录、文件等的位置起点整个树形目录结构中&#xff0c;使用独立的一个“/”表示常见的子目录目录目录名称目录目录名称/root管理员家目录/bin所有用户可执行命…

python动态绘图并保留之前绘图_[转]基于Python实现matplotlib中动态更新图片(交互式绘图)...

最近在研究动态障碍物避障算法&#xff0c;在Python语言进行算法仿真时需要实时显示障碍物和运动物的当前位置和轨迹&#xff0c;利用Anaconda的Python打包集合&#xff0c;在Spyder中使用Python3.5语言和matplotlib实现路径的动态显示和交互式绘图(和Matlab功能类似)。Anacond…

一步一步学Silverlight 2系列(25):综合实例之Live Search

概述 Silverlight 2 Beta 1版本发布了&#xff0c;无论从Runtime还是Tools都给我们带来了很多的惊喜&#xff0c;如支持框架语言Visual Basic, Visual C#, IronRuby, Ironpython&#xff0c;对JSON、Web Service、WCF以及Sockets的支持等一系列新的特性。《一步一步学Silverlig…

gateway中的局部过滤器_Spring Cloud Gateway中的过滤器工厂:重试过滤器

Spring Cloud Gateway基于Spring Boot 2&#xff0c;是Spring Cloud的全新项目&#xff0c;该项目提供了一个构建在Spring 生态之上的API网关。本文基于的Spring Cloud版本为Finchley M9&#xff0c;Spring Cloud Gateway对应的版本为2.0.0.RC1。Spring Cloud Gateway入门一文介…

cocos2d-x for android配置 运行 Sample on Linux OS

1.从http://www.cocos2d-x.org/download下载稳定版 比如cocos2d-x-2.2 2.解压cocos2d-x-2.2.zip,比如本文将其解压到 /opt 目录下 3.运行 android-buildsetup.sh,运行之前需要先设置3个环境变量,如将以下变量写到文件 /etc/profile中 export ANDROID_SDK_ROOT/opt/android-sdk-…

转变馆藏

您是否曾经想替换过HashSet或HashMap使用的equals和hashCode方法&#xff1f; 或者有一个List的一些元素类型伪装成的List相关类型的&#xff1f; 转换集合使这成为可能&#xff0c;并且本文将展示如何实现。 总览 转换集合是LibFX 0.3.0的一项功能&#xff0c;该功能将在今天…

Spring Boot和Swagger UI

我已经一年没有从头开始开发Spring Web应用程序了&#xff0c;如果我不参加QA自动化工程师的培训&#xff0c;那么这段时间甚至会更长。 由于这个原因&#xff0c;我开发了一个示例REST应用程序。 除了Swagger&#xff0c;一切对我来说都很熟悉。 因此&#xff0c;我将描述我在…