Kotlin协程实现非阻塞SpringBootWhy?SpringBoot默认使用ServletWeb服务器Tomcat,它为每个请求分配一个线程。如果服务不是计算密集型的,但是有大量的I/O等待,就??会浪费大量的CPU时间,导致CPU利用率低下。强行增大线程池会消耗大量内存,增加线程切换的损耗。因此,我们可以考虑使用ReactiveWeb服务器Netty,它基于事件循环,对于I/O密集型服务有着极高的性能。背景介绍我们有一个服务,需要对大量的对外接口进行封装调用,然后进行防腐转换和数据聚合。随着业务越来越复杂,接口的响应速度越来越慢,不能满足业务的延时要求。于是我们开始了第一轮的优化,使用CompletableFuture+线程池进行并发调用。经过一些操作,延迟降低了,但是资源利用率不高,单节点能承受的并发量很小。如果发生事件,并发需求增加,需要申请大量资源进行扩容,非常浪费。这时候我不禁要问了:为什么异步改造后并发能力还是不行呢?原因是整个服务模型还是阻塞I/O。异步调用的时候,虽然使用了新的线程,但是调用进程还是阻塞的,这个线程就阻塞了。当业务并发增加时,线程池中会产生大量阻塞线程,而且这些线程不是绿色线程(用户态线程),而是抢占式的,会带走宝贵的CPU时间,结果就是资源浪费利用。速率低,并发能力差。如何?为了解决I/O密集型服务并发度低的问题,可以改用Reactive模型。其实Spring早就有相应的解决方案:Reactor+WebFlux,可以实现非阻塞IO。响应式编程虽然很强大,但也有它的难点:它不是过程化的,写业务代码很难看懂,也很难调试和测试。响应式编程不是本文的重点。有兴趣的同学可以研究一下,从最早的RxJava到现在的ProjectReactor。那有更简单的解决方案吗?看一看:协程。Next:CoroutinesJava也有协程的解决方案叫Quasar(协程里面叫Fiber),但是18年了都没有更新。据说作者跑来写ProjectLoom。Loom是下一代Java协程库,但还不成熟,不可能投入生产。尽管Java没有协程,但JVM语言Kotlin有。接下来使用KotlinCoroutines结合WebFlux实现非阻塞的SpringBoot服务。假设有一个API,/slowInt,它在1s后返回一个整数。我们将调用它两次,然后计算总和。1s的响应时间有点极端,但是测试的时候比较容易看出区别。我们不妨分别使用非阻塞(WebClient)和阻塞(RestTemplate)Web客户端来做性能测试。importkotlinx.coroutines.*importorg.springframework.beans.factory.annotation.Autowiredimportorg.springframework.http.MediaType.APPLICATION_JSONimportorg.springframework.stereotype.Serviceimportorg.springframework.web.client.RestTemplateimportorg.springframework.web.client.getForObjectimportorg.springframework.web.reactive.function.client.WebClientimportorg.springframework.web.reactive.function.client.awaitBody@ServiceclassExampleService{@AutowiredlateinitvarwebClient:WebClient@AutowiredlateinitvarrestTemplate:RestTemplate/***使用协程*/suspendfunsumTwo():Int=coroutineScope{//区分异常调用,转换成getInt2()再测试一遍vali1:Deferred
