java 协程库 quasar demo

quasar 开源地址:https://github.com/puniverse/quasar

协程本质:单线程实现并行。

协程:适用于 IO 密集型。

线程池:适用于计算密集型。

Demo

假设我们有 100 个任务,每个任务需要做大量 IO (用 sleep 10秒 模拟)。

线程池实现

public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        List<Future> futures = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            final int count = i;
            Callable<Integer> callable = () -> {
                Thread.sleep(10000);
                return count;
            };
            Future future = executorService.submit(callable);
            futures.add(future);
        }

        System.out.println("start" + "  " + LocalDateTime.now().toString());

        Set<Future> finshed = new HashSet<>();
        while (finshed.size() < 100) {
            for (Future future : futures) {
                if (future.isDone() && !finshed.contains(future)) {
                    System.out.println(future.get() + "  " + LocalDateTime.now().toString());
                    finshed.add(future);
                }
            }
        }
    }

开 8 个线程并行。 

结果:

可见,耗费时间为 Math.ceil(100.0 / 8) * 10秒 : 130 秒。

start  2020-01-19T00:01:31.997
1  2020-01-19T00:01:41.978
2  2020-01-19T00:01:41.978
.......
99  2020-01-19T00:03:42.027

 协程实现

<dependency>
            <groupId>co.paralleluniverse</groupId>
            <artifactId>quasar-core</artifactId>
            <version>0.7.10</version>
            <classifier>jdk8</classifier>
        </dependency>
public static void main(String[] args) throws Exception {
        List<Fiber<Integer>> fibers = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            final int count = i;
            Fiber<Integer> fiber = new Fiber<>((SuspendableCallable<Integer>) () -> {
                Fiber.sleep(100000);
                return count;
            });
            fiber.start();
            fibers.add(fiber);
        }

        for (Fiber fiber : fibers) {
            System.out.println(fiber.get() + "  " + LocalDateTime.now().toString());
        }
    }

看看有多少个线程,发现:多了:

1 个 FiberTimedScheduler-default-fiber-pool 
8 个 ForkJoinPool-default-fiber-pool-worker 

也就是说对于 100 个任务,协程只用了 8 个 worker 线程。(为什么不是 1 个 worker 线程呢?可参考:https://blog.csdn.net/justsomebody126/article/details/104022982。协程与线程之间时多对多,这也是为了利用多 CPU 的特性。)

看输出结果,可见:

100 个任务同时完成。也就是说 8 个 worker 线程,每个 worker 负责的 12 个任务不是串行的,这也就是协程的本质:
单线程实现并行。
对于 IO 占时很长的任务来说,协程明显非常有优势。在同一个 Worker 线程中,如果当前任务遇到 IO,则把时间片让出给其他任务。这也是为什么所有任务能够同时完成。

0  2020-01-18T23:27:30.701
1  2020-01-18T23:27:30.702
2  2020-01-18T23:27:30.702
......
97  2020-01-18T23:27:30.706
98  2020-01-18T23:27:30.706
99  2020-01-18T23:27:30.706

内存消耗

  • 线程

如果使用线程来并发,想要并发度高,就要增加线程数。 但 JVM 每个线程默认栈内存 1M。

最大线程数量 =(Xmx - JVM分配的堆内存)/ Xss。显然线程数量大大受限。

  • 协程

而对于协程来说,其实多个协程只用到了1个线程。但这也并不代表每个协程自身就不占内存,但非常少,https://www.cnblogs.com/ll409546297/p/10945119.html 这篇文章说是 1K。

其他参考:

https://colobu.com/2016/07/14/Java-Fiber-Quasar/             这两个讲 Quasar 的基本原理的。

https://colobu.com/2016/08/01/talk-about-quasar-again/

http://docs.paralleluniverse.co/quasar/

https://zhuanlan.zhihu.com/p/27519705

https://zhuanlan.zhihu.com/p/27572086

https://zhuanlan.zhihu.com/p/27590299         java 的协程库

https://blog.csdn.net/guzhangyu12345/article/details/84666423      java 协程 quasar 从原理到代码应用

https://blog.csdn.net/guzhangyu12345/article/details/84257764      java协程之quasar初窥

微信协程改造:https://www.infoq.cn/article/CplusStyleCorourtine-At-Wechat/

不管是进程还是线程,每次阻塞、切换都需要陷入系统调用(system call),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪一个进程(线程)。而且由于抢占式调度执行顺序无法确定的特点,使用线程时需要非常小心地处理同步问题,而协程完全不存在这个问题(事件驱动和异步程序也有同样的优点)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值