java协程框架quasar和kotlin中的协程对比分析

目录
  • 前言
  • 快速体验
    • 添加依赖
    • 添加javaagent
  • 线程VS协程
    • 协程代码
    • 多线程代码
  • 协程完胜
  • 后记

前言

早就听说Go语言开发的服务不用任何架构优化,就可以轻松实现百万级别的qps。这得益于Go语言级别的协程的处理效率。协程不同于线程,线程是操作系统级别的资源,创建线程,调度线程,销毁线程都是重量级别的操作。而且线程的资源有限,在java中大量的不加限制的创建线程非常容易将系统搞垮。接下来要分享的这个开源项目,正是解决了在java中只能使用多线程模型开发高并发应用的窘境,使得java也能像Go语言那样使用协程的语义开发了。

快速体验

添加依赖

<dependency>
            <groupId>co.paralleluniverse</groupId>
            <artifactId>quasar-core</artifactId>
            <version>0.7.10</version>
</dependency>

注意:目前quasar最高的版本是0.8.0,但是最高版本的只支持jdk11以上

添加java agent

quasar的实现原理是在java加载class前,通过jdk的instrument机制使用asm来修改目标class的字节码来实现的,他标记了协程代码的起始和结束的位置,以及方法需要暂停的位置,每个协程任务统一由FiberScheduler去调度,内部维护了一个或多个ForkJoinPool实例。所以,在运行应用前,需要配置好quasar-core的java agent地址,在vm参数上加上如下脚本即可:

-javaagent:D:\.m2\repository\co\paralleluniverse\quasar-core\0.7.10\quasar-core-0.7.10.jar

线程VS协程

下面模拟调用某个远程的服务,假设远程服务处理耗时需要1S,这里使用执行阻塞1S来模拟,分别看多线程模型和协程模型调用这个服务10000次所需的耗时

协程代码

public static void main(String[] args) throws Exception{
        CountDownLatch count  = new CountDownLatch(10000);
        StopWatch stopWatch = new StopWatch();stopWatch.start();
        IntStream.range(0,10000).forEach(i-> new Fiber() {
            @Override
            protected String run() throws SuspendExecution, InterruptedException {
                Strand.sleep(1000 );
                count.countDown();
                return  "aa";
            }
        }.start());
        count.await();stopWatch.stop();
        System.out.println("结束了: " + stopWatch.prettyPrint());
    }

耗时情况:

多线程代码

public static void main(String[] args) throws Exception{
        CountDownLatch count  = new CountDownLatch(10000);
        StopWatch stopWatch = new StopWatch();stopWatch.start();
        ExecutorService executorService = Executors.newCachedThreadPool();
        IntStream.range(0,10000).forEach(i-> executorService.submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException ex) { }
            count.countDown();
        }));
        count.await();stopWatch.stop();
        System.out.println("结束了: " + stopWatch.prettyPrint());
    }

耗时情况

协程完胜

可以看到上面的结果,在对比访问一个耗时1s的服务10000次时,协程只需要2秒多,而多线程模型需要4秒多,时效相差了一倍。而且上面多线程编程时,并没有指定线程池的大小,在实际开发中是绝不允许的。一般我们会设置一个固定大小的线程池,因为线程资源是宝贵,线程多了费内存还会带来线程切换的开销。上面的场景在设置200个固定大小线程池时。结果也是可预见的达到了50多秒。这个结果足以证明协程编程ko线程编程了。而且在qps越大时,线程处理的效率和协程的差距就约明显,缩小差距的唯一方式就是增加线程数,而这带来的影响就是内存消耗激增。而反观协程,基于固定的几个线程调度,可以轻松实现百万级的协程处理,而且内存稳稳的。

后记

最后,博主以为Quasar只是一个框架层面的东西,所以就又去看了下同样是jvm语言的kotlin的协程。他的语言更简洁,可以直接和java混合使用。跑上面这种实例只需要1秒多。

fun main() {
    val count = CountDownLatch(10000)
    val stopWatch = StopWatch()
    stopWatch.start()
    IntStream.range(0,10000).forEach {
        GlobalScope.launch {
            delay(1000L)
            println(Thread.currentThread().name + "->"+ it)
            count.countDown()
        }
    }
    count.await()
    stopWatch.stop()
    println("结束了: " + stopWatch.prettyPrint())
}

当博主看到这个结果的时候,有种震惊的赶脚,kotlin的同步模型牛逼呀,瞬时感觉到发现了java里的骚操作了,可以使用kotlin的协程来代替java中的多线程操作。因为他们两个混合开发毫无压力。如果行的通,那就太爽了。所以就有下面这个kotlin协程实现的代码:

@Service
class KotlinAsyncService(private val weatherService: GetWeatherService,private val demoApplication: DemoApplication){
    val weatherUrl = "http://localhost:8080/demo/mockWeatherApi?city="
    fun getHuNanWeather(): JSONObject{
        val result = JSONObject()
        val count = CountDownLatch(demoApplication.weatherContext.size)
        for (city in demoApplication.weatherContext){
            val url = weatherUrl + city.key
            GlobalScope.launch {
                result[city.key.toString()] = weatherService.get(url)
                count.countDown()
            }
        }
        count.await()
        return result
    }
}

现实是,当我使用协程替换掉我java多线程写的一个多线程汇聚多个http接口的结果的接口时,通过ab压测他们两个的性能并没有很大的变化,最后了解到主要原因是这个时候,在协程里发起一个http的请求时,涉及到操作系统层面的socket io操作,io操作是阻塞的,协程的并发也就变成了调度协程的几个线程的并发了。而且当我把同样的代码放到Quasar中的时候,Quasar直接抛io异常了,说明Quasar还并不能轻松支持这个场景。那为什么上面的测试结果差距这么大呢,是因为我错误的把协程实现里的阻塞等同于线程的阻塞。协程里的delay挂起函数,会立马释放线程到线程池,但是当真正的io阻塞的时候也就和真正的线程sleep一样了,并没有释放当前的线程。所以这些对比都没有太大的意义

以上就是java协程框架quasar和kotlin中的协程对比分析的详细内容,更多关于java框架quasar和kotlin协程对比的资料请关注我们其它相关文章!

(0)

相关推荐

  • 利用Kotlin的协程实现简单的异步加载详解

    前言 众所周知在android中当执行程序的耗时超过5秒时就会引发ANR而导致程序崩溃.由于UI的更新操作是在UI主线程进行的,理想状态下每秒展示60帧时人眼感受不到卡顿,1000ms/60帧,即每帧绘制时间不应超过16.67ms.如果某项操作的耗时超过这一数值就会导致UI卡顿.因此在实际的开发中我通常把耗时操作放在一个新的线程中(比如从网络获取数据,从SD卡读取图片等操作),但是呢在android中UI的更新只能在UI主线程中进行更新,因此当我们在非UI线程中执行某些操作的时候想要更新UI就需

  • Java与kotlin详细对比

    在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言. 为什么选择 Kotlin? 简洁: 大大减少样板代码的数量. 安全: 避免空指针异常等整个类的错误. 互操作性: 充分利用 JVM.Android 和浏览器的现有库. 工具友好: 可用任何 Java IDE 或者使用命令行构建. 使用kotlin已经有一段时间了.打算从宏观上做一下java和kotlin的对比.java8虽然也有很多新特性,但是android低版本并不兼容.因此这里以旧版本

  • Kotlin与Java的区别详解

    什么是Kotlin? Kotlin是一种可以在 Java 虚拟机 (JVM) 上运行的开源编程语言.该语言可以在许多平台上运行. 它是一种将面向对象编程 (OOP) 和函数式编程结合在一个不受限制.自给自足且与众不同的平台中的语言. 什么是Java? Java 是一种多平台.面向对象.以网络为中心的编程语言.它是最常用的编程语言之一.它也用作计算平台,最早由 Sun Microsystem 于 1995 年发布,后来被 Oracle 公司收购. 主要区别: Kotlin 结合了面向对象和函数式编

  • 深入理解 Java、Kotlin、Go 的线程和协程

    前言 Go 语言比 Java 语言性能优越的一个原因,就是轻量级线程Goroutines(协程Coroutine).本篇文章深入分析下 Java 的线程和 Go 的协程. 协程是什么 协程并不是 Go 提出来的新概念,其他的一些编程语言,例如:Go.Python 等都可以在语言层面上实现协程,甚至是 Java,也可以通过使用扩展库来间接地支持协程. 当在网上搜索协程时,我们会看到: Kotlin 官方文档说「本质上,协程是轻量级的线程」. 很多博客提到「不需要从用户态切换到内核态」.「是协作式的

  • kotlin之协程的理解与使用详解

    前言         为什么在kotlin要使用协程呢,这好比去了重庆不吃火锅一样的道理.协程的概念并不陌生,在python也有提及.任何事务的作用大多是对于所依赖的环境相应而生的,协程对于kotlin这门语言也不例外.协程的优点,总的来说有如下几点:轻量级,占用更少的系统资源: 更高的执行效率: 挂起函数较于实现Runnable或Callable接口更加方便可控: kotlin.coroutine 核心库的支持,让编写异步代码更加简单.当然在一些不适应它的用法下以上优势也会成为劣势. 1.协程

  • java协程框架quasar和kotlin中的协程对比分析

    目录 前言 快速体验 添加依赖 添加javaagent 线程VS协程 协程代码 多线程代码 协程完胜 后记 前言 早就听说Go语言开发的服务不用任何架构优化,就可以轻松实现百万级别的qps.这得益于Go语言级别的协程的处理效率.协程不同于线程,线程是操作系统级别的资源,创建线程,调度线程,销毁线程都是重量级别的操作.而且线程的资源有限,在java中大量的不加限制的创建线程非常容易将系统搞垮.接下来要分享的这个开源项目,正是解决了在java中只能使用多线程模型开发高并发应用的窘境,使得java也能

  • hystrix配置中Apollo与Archaius对比分析

    目录 前言 ARCHAIUS警告日志 我们遇到的问题 HYSTRIX在FEIGN中的加载过程 SPRINGBOOT自动加载HYSTRIX HYSTRIX的动态兜底配置 APOLLO配置驱动HYSTRIX 结语 前言 feign是一个出色的Http请求客户端封装框架,feign-hystrix是整个框架体系里的其中一个模块,用来集成hystrix熔断器的,feign和hystrix这两个项目都是Netflix开源的(openfeign已独立迭代).在spring boot项目中,可以使用sprin

  • python中in在list和dict中查找效率的对比分析

    首先给一个简单的例子,测测list和dict查找的时间: import time query_lst = [-60000,-6000,-600,-60,-6,0,6,60,600,6000,60000] lst = [] dic = {} for i in range(100000000): lst.append(i) dic[i] = 1 start = time.time() for v in query_lst: if v in lst: continue end1 = time.time

  • 一文彻底搞懂Kotlin中的协程

    产生背景 为了解决异步线程产生的回调地狱 //传统回调方式 api.login(phone,psd).enquene(new Callback<User>(){ public void onSuccess(User user){ api.submitAddress(address).enquene(new Callback<Result>(){ public void onSuccess(Result result){ ... } }); } }); //使用协程后 val use

  • nodejs中Express与Koa2对比分析

    知会上看到有个问题 <Express会被Koa2取代吗?> .刚好对Express.koa有点小研究,于是简单回答了一下. 1.先说结论 目前没有看到Express会被koa2取代的迹象. 目前来说,Express的生态更成熟,入门门槛相对较低.从npm上的下载热度来说,两者的差距还较大,Express的月下载量约为koa2的40倍. 不过koa2的亮点足够吸引人,生态也开始变得完善. 2.从使用门槛来说 从使用上来说,Express对初学者更有好些,对着官网修修改改改就能做点东西出来. ko

  • C++20中的协程(Coroutine)的实现

    C++20中的协程(Coroutine) 从2017年开始, 协程(Coroutine)的概念就开始被建议加入C++20的标准中了,并已经开始有人对C++20协程的提案进行了介绍.1事实上,协程的概念在很早就出现了,甚至其他语言(JS,Python,C#等)早就已经支持了协程. 可见,协程并不是C++所特有的概念. 那么,什么是协程? 简单来说,协程就是一种特殊的函数,它可以在函数执行到某个地方的时候暂停执行,返回给调用者或恢复者(可以有一个返回值),并允许随后从暂停的地方恢复继续执行.注意,这

  • Java8中Optional类型和Kotlin中可空类型的使用对比

    本文主要给大家介绍了关于Java8中Optional类型和Kotlin中可空类型使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 在 Java 8中,我们可以使用 Optional 类型来表达可空的类型. package com.easy.kotlin; import java.util.Optional; import static java.lang.System.out; /** * Optional.ofNullable - 允许传递为 null 参数 *

  • Kotlin中协程的创建过程详析

    目录 为什么需要协程? 创建并启动协程 协程的执行过程 suspend block 是如何变为协程体被执行的? 总结 总结 为什么需要协程? 协程可以简化异步编程,可以顺序地表达程序,协程也提供了一种避免阻塞线程并用更廉价.更可控的操作替代线程阻塞的方法 – 挂起函数. Kotlin 的协程是依靠编译器实现的, 并不需要操作系统和硬件的支持.编译器为了让开发者编写代码更简单方便, 提供了一些关键字(例如suspend), 并在内部自动生成了一些支持型的代码. 创建并启动协程 fun create

  • 基于asyncio 异步协程框架实现收集B站直播弹幕

    前言 虽然标题是全站,但目前只做了等级 top 100 直播间的全天弹幕收集. 弹幕收集系统基于之前的B 站直播弹幕姬 Python 版修改而来.具体协议分析可以看上一篇文章. 直播弹幕协议是直接基于 TCP 协议,所以如果 B 站对类似我这种行为做反制措施,比较困难.应该有我不知道的技术手段来检测类似我这种恶意行为. 我试过同时连接 100 个房间,和连接单个房间 100 次的实验,都没有问题.>150 会被关闭链接. 直播间的选取 现在弹幕收集系统在选取直播间上比较简单,直接选取了等级 to

  • go语言中的协程详解

    协程的特点 1.该任务的业务代码主动要求切换,即主动让出执行权限 2.发生了IO,导致执行阻塞(使用channel让协程阻塞) 与线程本质的不同 C#.java中我们执行多个线程,是通过时间片切换来进行的,要知道进行切换,程序需要保存上下文等信息,是比较消耗性能的 GO语言中的协程,没有上面这种切换,一定是通过协程主动放出权限,不是被动的. 例如: C# 中创建两个线程 可以看到1和2是交替执行的 Go语言中用协程实现一下 runtime.GOMAXPROCS(1) 这个结果就是 执行了1 在执

随机推荐