从 Reactive 到 WebFlux 1

OK,还记得我开博客的第一篇文章就是想好好学习一下WebFlux,前段时间学习SpringBoot也就是想慢慢的学到这里来,然后和大家分享一下,在讲之前大家可以看看函数式编程基础了解一下。

在讲之前我想提一些问题,我们是否经常在网上看到这样一些关于reactive的讲法:
       1.Reactive 是异步非阻塞编程
       2.Reactive 能够提升程序性能
       3.Reactive 解决传统编程模型遇到的困境

在讲解reactive之前,我们还是从传统的编程模型说起:

传统的编程模型往往是阻塞式的,那么有办法对传统编程模型进行改进吗?一般来说有两种方法

1. parallelize: use more threads and more hardware resources.
2. seek more efficiency in how current resources are used

一种是多线程,另一种就是资源有限(例如CPU)情况下,尽可能最大化CPU。

但是Reactor 认为阻塞可能是浪费的:
1.阻塞导致性能瓶颈和浪费资源
2.增加线程可能会引起资源竞争和并发问题
3.并行的方式不是银弹(不能解决所有问题)

我们看一个阻塞式的编程:

public class DataLoader {

    public final void load() {
        long startTime = System.currentTimeMillis(); // 开始时间
        doLoad(); // 具体执行
        long costTime = System.currentTimeMillis() - startTime; // 消耗时间
        System.out.println("load() 总耗时:" + costTime + " 毫秒");
    }

    protected void doLoad() { // 串行计算
        loadConfigurations();    //  耗时 1s
        loadUsers();                  //  耗时 2s
        loadOrders();                // 耗时 3s
    } // 总耗时 1s + 2s  + 3s  = 6s

    protected final void loadConfigurations() {
        loadMock("loadConfigurations()", 1);
    }

    protected final void loadUsers() {
        loadMock("loadUsers()", 2);
    }

    protected final void loadOrders() {
        loadMock("loadOrders()", 3);
    }

    private void loadMock(String source, int seconds) {
        try {
            long startTime = System.currentTimeMillis();
            long milliseconds = TimeUnit.SECONDS.toMillis(seconds);
            Thread.sleep(milliseconds);
            long costTime = System.currentTimeMillis() - startTime;
            System.out.printf("[线程 : %s] %s 耗时 :  %d 毫秒\n",
                    Thread.currentThread().getName(), source, costTime);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        new DataLoader().load();
    }

}

由于串行执行的关系,导致消耗实现线性累加。Blocking 模式即串行执行 。

那我们变成并行的方式又会怎样呢?

public class ParallelDataLoader extends DataLoader {

    protected void doLoad() {  // 并行计算
        ExecutorService executorService = Executors.newFixedThreadPool(3); // 创建线程池
        CompletionService completionService = new ExecutorCompletionService(executorService);
        completionService.submit(super::loadConfigurations, null);      //  耗时 >= 1s
        completionService.submit(super::loadUsers, null);               //  耗时 >= 2s
        completionService.submit(super::loadOrders, null);              //  耗时 >= 3s

        int count = 0;
        while (count < 3) { // 等待三个任务完成
            if (completionService.poll() != null) {
                count++;
            }
        }
        executorService.shutdown();
    }  // 总耗时 max(1s, 2s, 3s)  >= 3s

    public static void main(String[] args) {
        new ParallelDataLoader().load();
    }

}

明显地,程序改造为并行加载后,性能和资源利用率得到提升,消耗时间取最大者

延伸思考
1. 如果阻塞导致性能瓶颈和资源浪费的话,Reactive 也能解决这个问题?
2. 为什么不直接使用 Future#get() 方法强制所有任务执行完毕,然后再统计总耗时?
3. 由于以上三个方法之间没有数据依赖关系,所以执行

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值