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跑操作系統的調度程序,然後再由調度程序決定該跑哪一個進程(線程)。而且由於搶佔式調度執行順序無法確定的特點,使用線程時需要非常小心地處理同步問題,而協程完全不存在這個問題(事件驅動和異步程序也有同樣的優點)

發佈了40 篇原創文章 · 獲贊 1 · 訪問量 3408
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章