java 协程quasar教程,kotlin协程和线程的区别

  java 协程quasar教程,kotlin协程和线程的区别

  00-1010前言快速体验添加依赖添加java代理线程VS协同代码多线程代码协同胜利后记

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

  Quasar项目地址:https://github.com/puniverse/quasarquasar周边项目地址:https://github.com/puniverse/comsat

  

目录

 

  00-1010依赖groupIdco.paralleluniverse/groupId神器quasar-core/神器ID版本0 . 7 . 10/version/依赖注:目前Quasar最高版本为0.8.0,但最高版本仅支持jdk11及以上版本。

  

前言

quasar的实现原理是在java加载类之前,通过jdk的instrument机制用asm修改目标类的字节码。他标记协同代码的开始和结束位置以及该方法需要暂停的位置。每个协同任务由FiberScheduler统一调度,内部维护一个或多个ForkJoinPool实例。因此,在运行应用程序之前,您需要配置quasar-core的java代理地址,并将以下脚本添加到vm参数中:

 

  -Java agent :d : . m2 repository co parallel universe quasar-core 0 . 7 . 10 quasar-core-0 . 7 . 10 . jar

  00-1010以下模拟调用一个远程服务,假设远程服务处理需要1秒钟。这里用执行阻塞1S来模拟,多线程模型和协同进程模型分别调用这个服务10000次所需的时间。

  

快速体验

public static void main(String[]args)抛出异常{ CountDownLatch count=new CountDownLatch(10000);秒表秒表=新秒表();秒表. start();IntStream.range(0,10000)。forEach(I-new Fiber(){ @ Override protected String run()抛出SuspendExecution,interrupted exception { strand . sleep(1000);count . count down();返回‘aa’;} }.start());count . await();秒表. stop();system . out . println( ended : stopwatch . pretty print());}耗时情况:

 

  

添加依赖

public static void main(String[]args)抛出异常{ CountDownLatch count=new CountDownLatch(10000);秒表秒表=新秒表();秒表. start();执行者服务=执行者。

 

  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协程实现的代码:

 

  

@Serviceclass 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协程对比的资料请关注盛行IT其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: