37

我一直在学习和尝试使用 Reactor 和 RxJava 的反应式编码。我确实明白,与单线程执行相比,反应式编码可以更好地利用 CPU。

在基于 Web 的应用程序中,反应式编程与命令式编程之间是否有任何具体的比较?

通过使用反应式编程而不是非反应式编程,我获得的性能增益和吞吐量是多少?

还有反应式编程的优缺点是什么?

有没有统计基准?

4

6 回答 6

39

好吧,反应式编程意味着您正在异步执行所有 IO 绑定任务,例如网络调用。例如,您的应用程序调用外部 REST API 或数据库,您可以异步执行该调用。如果这样做,您当前的线程不会阻塞。您可以通过仅生成一个或几个线程来处理大量请求。如果您遵循阻塞方法,您需要有一个线程来处理每个请求。您可以参考我的多部分博客文章第 1部分、第 2 部分第 3 部分了解更多详细信息。

除此之外,您可以使用回调来做同样的事情。您可以使用回调进行异步调用。但如果你这样做,有时你可能会以回调地狱告终。在另一个回调中包含一个回调会导致非常复杂的代码,这些代码很难维护。另一方面,RxJava 让你可以编写更简单、可组合和可读的异步代码。此外,RxJava 还为您提供了许多强大的运算符,例如 Map、Zip 等,这使您的代码更加简单,同时由于不依赖于彼此的不同任务的并行执行而提高了性能。

RxJava 不是另一个具有一组运算符的 Observer 实现,而是它为您提供了非常方便的良好错误处理和重试机制。

但是我还没有使用命令式编程方法对 RxJava 进行任何基准测试,以在统计上向您推荐。但我非常确定 RxJava 应该比阻塞机制产生更好的性能。

更新

由于随着时间的推移我积累了更多的经验,我想在我的答案中增加更多的分数。

基于这篇文章,ReactiveX 是一个使用可观察序列组成异步和基于事件的程序的库。我认为您首先要阅读这篇介绍性文章。

这些是响应式系统的一些属性:事件驱动、可扩展、弹性、响应

对于 RxJava,它为程序员提供了两个主要功能。首先,它提供了一个很好的可组合 API,使用了一组丰富的运算符,例如 zip、concat、map 等。这会产生更简单和可读的代码。谈到代码,可读性和简单性是最重要的属性。其次,它提供了出色的抽象,使并发成为声明性的。

一个流行的误解是 Rx 默认是多线程的。事实上,Rx 默认是单线程的。如果你想异步做事,那么你必须通过传递相关的调度程序来明确地告诉它使用subscribeOn和运算符。observeOnRxJava 为您提供线程池来执行异步任务。调度器有很多,比如IO,Computation等等。IO调度器,顾名思义,最适合IO密集型任务,例如网络调用等。相反,计算调度器更适合CPU密集型计算任务。你也可以用 RxJava 连接你自己的 Executor 服务。内置的调度器主要帮助你摆脱维护自己的 Executor 服务,让你的代码更简单。

最后谈谈 subscribeOn 和 observeOn

在 Rx 世界中,通常有两件事需要控制并发模型:

  1. 订阅的调用
  2. 通知的观察

SubscribeOn:指定 Observable 将在其上运行的调度程序。

ObserveOn:指定观察者将在其上观察此 Observable 的调度程序

于 2017-02-06T07:45:32.577 回答
10

缺点

  • 大多数时候存储数据流需要更多的内存(因为它是基于时间流的)。
  • 一开始学习可能会觉得非常规(需要一切都是流)。
  • 大多数复杂性必须在宣布新服务时处理。
  • 缺乏好的和简单的学习资源。

  • 经常被混淆为等同于函数响应式编程。

于 2017-08-29T12:00:12.230 回答
6

除了在其他响应中已经提到的关于无阻塞特性的内容之外,关于响应式编程的另一个重要特性是背压的重要使用。通常,它用于您的发布者发出的信息超出您的消费者可以处理的信息的情况。

因此,拥有这种机制,您可以控制两者之间的流量并避免令人讨厌的内存不足问题。

你可以在这里看到一些反应式编程的实际例子:https ://github.com/politrons/reactive

关于这里的背压:https ://github.com/politrons/Akka/blob/master/src/main/scala/stream/BackPressure.scala

顺便说一句,反应式编程的唯一缺点是学习曲线,因为您正在改变编程范式。但如今,所有重要的公司都尊重并遵循被动宣言

于 2017-02-06T08:47:51.567 回答
3

优点

  1. 代码更简洁,更简洁
  2. 更容易阅读(一旦你掌握了它)
  3. 更容易扩展(管道任何操作)
  4. 更好的错误处理
  5. 事件驱动的启发 -> 与流(Kafka、RabbitMQ 等)配合得很好
  6. 背压(客户端可以控制流量)

缺点

  1. 在某些情况下可能会变得更加占用内存
  2. 有点陡峭的学习曲线
于 2019-07-06T19:59:50.817 回答
3

反应式编程是一种涉及智能路由和事件消费的微架构。

反应式是您可以事半功倍,特别是您可以用更少的线程处理更高的负载。

反应类型并不是为了让您更快地处理您的请求或数据。它们的优势在于它们能够同时处理更多请求,以及更有效地处理具有延迟的操作,例如从远程服务器请求数据。

它们允许您通过在不消耗更多资源的情况下本地处理时间和延迟来提供更好的服务质量和可预测的容量规划。

来自
https://blog.redelastic.com/what-is-reactive-programming-bc9fa7f4a7fc https://spring.io/blog/2016/06/07/notes-on-reactive-programming-part-i-the-反应式景观 https://spring.io/blog/2016/07/28/reactive-programming-with-spring-5-0-m1

于 2017-10-23T08:42:13.833 回答
-7

反应式编程是一种命令式编程。反应式编程是一种并行编程。仅当您设法创建并行分支时,您才能获得超过单线程执行的性能。它们是由多个线程执行,还是由响应式构造(实际上是异步过程)执行,并不重要。

与多线程编程相比,反应式编程的唯一优势是内存消耗较低(每个线程需要 0.5...1 兆字节)。缺点是不太容易编程。

更新(2020 年 8 月)。并行编程可以有两种风格:多线程编程,主要活动是线程,异步编程,主要活动是异步过程(包括参与者,它们是可重复的异步过程)。在多线程编程中,使用了各种通信方式:无界队列、有界(阻塞)队列、二进制和计数信号量、countdownLatches 等。而且。总有可能创造自己的沟通方式。在异步编程中,直到最近,只使用了 2 种通信器:用于不可重复异步过程的 future 和用于 actor 的无界队列。当生产者工作得比消费者快时,无界队列会导致问题。为了解决这个问题,发明了新的通信协议:反应流,这是无界队列和计数(异步)信号量的组合,使队列有界。这直接类似于多线程编程中的阻塞队列。使用响应式流进行编程被自豪地称为反应式编程(想象一下,如果在多线程编程中,使用阻塞队列进行编程称为阻塞编程)。但同样,没有向异步程序员提供创建自己的通信工具的方法。并且异步信号量不能单独使用,只能作为反应流的一部分。也就是说,异步编程理论,包括反应式编程理论,远远落后于多线程编程理论。

反应流的一个奇特补充是映射/过滤功能,允许编写线性管道,如

 publisher
     .map(()->mappingFunction)
     .filter(()->filterFunction)
     .flatmap(...)

等等。但这不是反应式编程的独有特性。这允许只创建线性管道,而在多线程编程中,很容易创建任意拓扑的计算图。

 

于 2018-11-02T17:47:20.120 回答