天天看點

Java 中的協程庫 - Quasar

一、協程

一個程序可以産生許多線程,每個線程有自己的上下文,當我們在使用多線程的時候,如果存在長時間的 I/O 操作,線程會一直處于阻塞狀态,這個時候會存在很多線程處于空閑狀态,會造成線程資源的浪費。這就是協程适用的場景。

協程,其實就是在

一個線程

中,有一個總排程器,對于多個任務,同時隻有一個任務在執行,但是一旦該任務進入阻塞狀态,就将該任務設定為挂起,運作其他任務,在運作完或者挂起其他任務的時候,再檢查待運作或者挂起的任務的狀态,使其繼續執行。

協程的方式更多用來做阻塞密集型(比如 I/O)的操作,計算密集型的還是使用線程更加合理。

Java 官方并沒有協程庫。但是偉大的社群提供了一個優秀的庫,它就是 Quasar。

OpenJDK 在2018年建立了 Loom 項目,這是 Java 用來應對協程的官方解決方案,不過目前尚沒有完整的釋出日期,Java 使用者可以期待一下。

二、Quasar 簡介

Quasar 提供了高性能輕量級的線程,提供了類似 Go 的 channel,Erlang 的 actor,以及其它的異步程式設計的工具,可以用在 Java 和 Kotlin 程式設計語言中。

Quasar 最主要的貢獻就是提供了輕量級線程的實作 —— fiber。Fiber 的功能和使用類似 Thread, API 接口也類似,是以使用起來沒有違和感,但是它們不是被作業系統管理的,它們是由一個或者多個 ForkJoinPool 排程。一個空閑的 fiber 隻占用 400 位元組記憶體,切換的時候占用更少的 CPU,你的應用中可以有上百萬的 fiber,顯然Thread 做不到這一點。

Fiber 特别适合替換那些異步回調的代碼。使用 FiberAsync 異步回調很簡單,而且性能很好,擴充性也更高。

那麼我們為什麼稱 Quasar 為協程庫呢?實際上 Quasar 的實作就是想辦法讓運作中的線程棧停下來,好讓 Quasar 的排程器介入,JVM 線程中斷的條件隻有兩個:一個是抛異常;另外一個就是 return。這裡 Quasar 就是通過抛異常(SuspendExecution)的方式來達到的,這樣就完成了以線程的方式實作協程。

三、Quasar 配置

首先我們需要在 pom.xml 中引入 Quasar 的 jar 包(0.8.0 版本支援 jdk11 或更高的版本):

<dependency>
      <groupId>co.paralleluniverse</groupId>
      <artifactId>quasar-core</artifactId>
      <version>0.7.4</version>
      <classifier>jdk8</classifier>
    </dependency>
           

Quasar fiber 依賴 java instrumentation 修改你的代碼,可以在運作時通過 java Agent 實作,也可以在編譯時使用 ant task實作。

通過 java agent 很簡單,在程式啟動的時候将下面的指令加入到指令行,注意把 path-to-quasar-jar.jar 替換成你實際的 quasar java 的位址:

-javaagent:path-to-quasar-jar.jar
-javaagent:C:\Users\Administrator\.m2\repository\co\paralleluniverse\quasar-core\0.7.3\quasar-core-0.7.3.jar
           

對于 maven 來說,你可以使用插件 maven-dependency-plugin,它會為你的每個依賴設定一個屬性,以便在其它地方引用,我們主要想使用 ${co.paralleluniverse:quasar-core:jar}

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
        <execution>
            <id>getClasspathFilenames</id>
            <goals>
                <goal>properties</goal>
            </goals>
        </execution>
     </executions>
</plugin>
           

然後你可以配置 exec-maven-plugin 或者 maven-surefire-plugin 加上 agent 參數,在執行 maven 任務的時候就可以使用 Quasar 了。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <!-- Turn off before production -->
        <argLine>-Dco.paralleluniverse.fibers.verifyInstrumentation=true</argLine>

        <!-- Enable if using compile-time (AoT) instrumentation -->
        <!-- argLine>-Dco.paralleluniverse.fibers.disableAgentWarning</argLine -->

        <!-- Quasar Agent for JDK 7 -->
        <!-- argLine>-javaagent:${co.paralleluniverse:quasar-core:jar}</argLine-->

        <!-- Quasar Agent for JDK 8 -->
        <argLine>-javaagent:${co.paralleluniverse:quasar-core:jar:jdk8}</argLine>
    </configuration>
</plugin>
           

官方提供了一個 Quasar Maven archetype,你可以通過下面的指令生成一個quasar應用原型:

git clone https://github.com/puniverse/quasar-mvn-archetype
cd quasar-mvn-archetype
mvn install
cd ..
mvn archetype:generate -DarchetypeGroupId=co.paralleluniverse -DarchetypeArtifactId=quasar-mvn-archetype -DarchetypeVersion=0.7.4 -DgroupId=testgrp -DartifactId=testprj
cd testprj
mvn test
mvn clean compile dependency:properties exec:exec
           

如果你使用 gradle,可以看一下 gradle 項目模闆:Quasar Gradle template project。

詳細配置可以參考 specifying-the-java-agent-with-maven

四、Quasar 使用

Quasar 的核心是 Fiber 類,Fiber 繼承自 Future,有一個傳回值,類型為泛型 V,Fiber 的使用和 Thread 類似,

new Fiber<Void>() {
            @Override
            protected Void run() throws SuspendExecution, InterruptedException {
                System.out.println("Hello Fiber");
                return null;
            }
        }.start();
           

你可以傳遞 SuspendableRunnable 或 SuspendableCallable 給Fiber的構造函數:

new Fiber<>(() -> {
            System.out.println("Hello Fiber");
            return null;
        }).start();
           

五、Comsat 介紹

Comsat 又是什麼?

Comsat 還是 Parallel Universe 提供的內建 Quasar 的一套開源庫,可以提供 web 或者企業級的技術,如 HTTP 服務和資料庫通路。

Comsat 并不是一套 web 架構。它并不提供新的 API,隻是為現有的技術如 Servlet、JAX-RS、JDBC 等提供 Quasar fiber 的內建。

它包含非常多的庫,比如 Spring、ApacheHttpClient、OkHttp、Undertow、Netty、Kafka 等。

推薦閱讀:

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

Java中的纖程庫 - Quasar

繼續了解Java的纖程庫 - Quasar