kotlin彙總7-Coroutines

在kotlin1.1,Coroutines還處於實驗階段。
有些API啓動耗時操作比如:網絡IO,文件流IO,CPU/GPU要求高的工作,它們會導致調用阻塞直到操作完成。Coroutines通過一種更便宜,更容易控制的suspension(掛起)操作,來避免線程阻塞。

Coroutines把複雜的運算移到了libraries,因而簡化了異步編程。在Coroutine中,程序邏輯可以順序表達(同步),底層的libraries可以幫我們完成異步操作,我們只需要在異步回調中編寫我們的代碼就完成了,可以在不同的線程訂閱相關的事情,執行計劃,代碼就像順序執行一樣簡單。

像其他語言中的大多數異步機制都可以通過coroutines實現。包括C#和ECMAScript的async/await,Go的channels和select, C#和Python的generator/yeild.

阻塞VS掛起
基本上,coroutines可以掛起運算而不會阻塞線程。阻塞線程通常代價昂貴,特別是在高負載的情況下,因爲在真實的情境下,僅僅會很少的幾個線程會在運行,所以阻塞其中一個線程會導致很多重要的工作會被延遲。

換句話說,Coroutine基本上是無代價的。不需要切換上下文,也不需要任何OS的參與。在這基礎上,suspension可以在很大程度上被使用者library控制,作爲一個library的開發者,我們可以決定suspension的時候做什麼,比如優化/打印/攔截,完全可以根據我們自己的需要。

不同的地方是,Coroutines不能被隨時掛起,僅僅是在調用函數的時候。

通過suspend定義一個掛起函數

suspend fun doSomething(foo: Foo): Bar {
    ...
}

在kotlinx.coroutines中有

fun <T> async(block: suspend () -> T)

所以我們可以如下調用

async {
    doSomething(foo)
    ...
}

但是我們需要注意,不能在一個普通的函數如main()中調用掛起函數

fun main(args: Array<String>) {
    doSomething() // ERROR: Suspending function called from a non-coroutine context 
}

而且掛起函數可以是虛函數,可以被子類覆寫

interface Base {
    suspend fun foo()
}

class Derived: Base {
    override suspend fun foo() { ... }
}

使用@RestrictsSuspension註釋可以使用者定義新的掛起方式,最經典的例子是

@RestrictsSuspension
@SinceKotlin("1.1")
public abstract class SequenceBuilder<in T> internal constructor() {
    /**
     * Yields a value to the [Iterator] being built.
     *
     * @sample samples.collections.Sequences.Building.buildSequenceYieldAll
     * @sample samples.collections.Sequences.Building.buildFibonacciSequence
     */
    public abstract suspend fun yield(value: T)

    /**
     * Yields all values from the `iterator` to the [Iterator] being built.
     *
     * The sequence of values returned by the given iterator can be potentially infinite.
     *
     * @sample samples.collections.Sequences.Building.buildSequenceYieldAll
     */
    public abstract suspend fun yieldAll(iterator: Iterator<T>)

    /**
     * Yields a collections of values to the [Iterator] being built.
     *
     * @sample samples.collections.Sequences.Building.buildSequenceYieldAll
     */
    public suspend fun yieldAll(elements: Iterable<T>) {
        if (elements is Collection && elements.isEmpty()) return
        return yieldAll(elements.iterator())
    }

因爲SequenceBuilder類的成員函數都是掛起函數,設計者不希望使用者添加新的掛起函數,所以可以使用@RestrictsSuspension做了限制。

Coroutines的內部工作機制,這個比較複雜,使用是的編譯器技巧,有興趣可以看英文資料Coroutines

需要注意是的,Coroutines目前還處於實驗階段。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章