响应式编程-reactor

什么是响应式编程

正如我们所知道的过程式编程、命令式编程、面向对象编程、事件驱动编程范式,响应式编程也是编程范式的一种。

基础介绍

reactor作为一种响应式编程具体实现,能够跟踪异步场景下的数据流和数据状态变更。在Java9中已经集成了响应式编程的接口,类名为Flow。

现在的硬件已经非常厉害了,但是随着并发量的增加,仍然会达到瓶颈。现在主要有两个方式解决程序的系统:

(1)并行:单机维度增加线程,集群维度扩机器;

(2)高效的资源利用:寻找更有效的方式利用当前已有的资源;

现在我们传统的做法是写阻塞式的代码,如果出现性能瓶颈,可能会想办法提升并发度,但是这种方式可能会导致竞争和并发等问题。更糟糕的是,可能由于等待IO资源,导致线程一直处于空闲等待,导致资源浪费。

目前在jvm中听过了两种异步编程的模式:Callbacks、Futures。

Callbacks模式很难实现组合,从而导致读和理解都较困难,而Futures模式比Callbacks模式好一些,但是也存在多种问题:不支持懒计算、缺失多值及错误处理等机制。

多种异步写法的比较

Callbacks写法

java 复制代码
// 定义回调接口
interface Callback {
    void callback(String res);
}

// 异步回调模拟调用
public void asyncWork(Callback callback) {
    new Thread(()->{
        // 先做某些事情
        String s = doSomething();
        // 等事情做完之后,执行回调函数
        callback.callback(s);
    }).start();
}

// 模拟做的事情
private String doSomething() {
    try{
        Thread.sleep(5000);
    }catch (Exception ignored){}
    return "test";
}

Futures写法

java 复制代码
// 异步执行
CompletableFuture.runAsync(() ->{
    doSomething();
});

// 模拟做的事情
private String doSomething() {
    try{
        Thread.sleep(5000);
    }catch (Exception ignored){}
    return "test";
}

Reactor写法

java 复制代码
@Test
public void test10() {
    // 创建一个流式数据
    Flux<String> flux = Flux.just("a", "b", "c");
    // 在一个异步调度器中执行数据打印
    flux.subscribeOn(Schedulers.parallel())
            .subscribe(System.out::println);
}

优缺点

优点

  • 非阻塞式;
  • 更好的资源利用;
  • 可组合性;
  • 错误处理;

缺点

  • 学习曲线可能复杂些;
  • 调试麻烦些;
  • 过度使用可能导致性能问题;

使用方式

引入依赖包

xml 复制代码
<dependencyManagement> 
    <dependencies>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-bom</artifactId>
            <version>2023.0.11</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-core</artifactId> 
        
    </dependency>
    <dependency>
        <groupId>io.projectreactor</groupId>
        <artifactId>reactor-test</artifactId> 
        <scope>test</scope>
    </dependency>
</dependencies>

进行Flux或者Mono封装

java 复制代码
@Test
public void test3() {
    Mono<String> future1 = Mono.fromCallable(() -> {
        Thread.sleep(5000);
        return "Result 1";
    }).subscribeOn(Schedulers.elastic());

    Mono<String> future2 = Mono.fromCallable(() -> {
        Thread.sleep(5000);
        return "Result 2";
    }).subscribeOn(Schedulers.elastic());
    long start = System.currentTimeMillis();
    Mono<List<String>> mono = Flux.merge(future1, future2)
            .collectList()
            .timeout(Duration.ofSeconds(9));
    List<String> res = mono.block();
    System.out.println(res);
    System.out.println("cost:" + (System.currentTimeMillis() - start));
}

@Test
public void test9() {
    Mono<String> mono = Mono.fromSupplier(()-> {
        try {
            System.out.println("name:" + Thread.currentThread().getName());
            Thread.sleep(5000);
        }catch (Exception e){

        }
        return "hello";
    });
    long start = System.currentTimeMillis();
    mono.subscribeOn(Schedulers.parallel())
                    .block();
    System.out.println("cost:" + (System.currentTimeMillis() - start));
}

Q&A

Q:publishOn和subscribeOn的区别

A:参考下面文档:

https://blog.csdn.net/qq_33797928/article/details/105005629

https://juejin.cn/post/7147655449695748126

https://juejin.cn/post/7251894360722292792

个人思考

1、计算机涉及多种资源,比如:CPU资源、IO资源(网络设备、存储设备)等,如果很容易出现资源瓶颈,会导致计算机资源没法充分利用。比如当CPU资源使用率为30%时,IO资源使用率已达到100%,这时候会导致CPU资源出现严重的浪费。如果能通过合理的系统调度,保证CPU、IO等资源都能进行合理的利用,可能会导致整体的性能有很大的提升。

参考文档

1、reactor问题社区

https://stackoverflow.com/questions/tagged/reactor

2、官方文档

https://projectreactor.io/docs/core/release/reference/#_blocking_can_be_wasteful

相关推荐
2401_8574396929 分钟前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna1 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
Dream_Snowar2 小时前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石3 小时前
12/21java基础
java