-
协程(Coroutine),其实是go,lua,erlang的原声语言,其实JVM上也有蛮多的实现,如PicoThread,Kilim,Quasar等,本文主要介绍其中一种Coroutine实现
– Quasar Fiber,Quasar Fiber相对来说流行度更好一些 -
相比于os thread,fiber不管在内存资源还是调度上都比前者轻量的多,相对于thread blocking, fiber blocking可以达到比前者大几个数量级的并发度,更有效的利用CPU资源(运行fiber的worker线程并没有block)
-
虽然Java的线程的API封装的很好,使用起来非常的方便,但是使用起来也得小心。首先线程需要耗费资源,所以单个的机器上创建上万个线程很困难,其次线程之间的切换也需要耗费CPU,在线程非常多的情况下导致很多CPU资源耗费在线程切换上,通过提高线程数来提高系统的性能有时候适得其反。你可以看到现在一些优秀的框架如Netty都不会创建很多的线程,默认2倍的CPU core的线程数就已经应付的很好了,比如node.js可以使用单一的进程/线程应付高并发。
-
Quasar最主要的贡献就是提供了轻量级线程的实现,叫做fiber(纤程)。Fiber的功能和使用类似Thread,
-
API接口也类似,所以使用起来没有违和感,但是它们不是被操作系统管理的,它们是由一个或者多个ForkJoinPool调度。一个idle
fiber只占用400字节内存,切换的时候占用更少的CPU,你的应用中可以有上百万的fiber,显然Thread做不到这一点。这一点和Go的goroutine类似。 -
Fiber并不意味着它可以在所有的场景中都可以替换Thread。当fiber的代码经常会被等待其它fiber阻塞的时候,就应该使用fiber。
对于那些需要CPU长时间计算的代码,很少遇到阻塞的时候,就应该首选thread -
以上两条是选择fiber还是thread的判断条件,主要还是看任务是I/O blocking相关还是CPU相关。幸运地是,fiber API使用和thread使用类似,所以代码略微修改久就可以兼容。
-
协程流程:将所有的任务放到一个队列中,执行execute方法后,新开辟一个线程用于执行所有的任务,当遇到io阻塞的时候,让出当前执行权,将该任务放回队列执行io,cpu执行队列中下一个任务。
package com.snsndk.baselibs.parallel;
import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.strands.concurrent.CountDownLatch;
import com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* Created on 2020-01-01
* <p>Copyright 2008-2020 snsndk.com</p>
*
*/
@Slf4j
public class ParallelTask {
private final