亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kotlin續體、續體攔截器和調度器實例分析

發布時間:2022-08-01 14:02:17 來源:億速云 閱讀:118 作者:iii 欄目:開發技術

本篇內容介紹了“Kotlin續體、續體攔截器和調度器實例分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

一.Continuation

Continuation接口是協程中最核心的接口,代表著掛起點之后的續體,代碼如下:

public interface Continuation<in T> {
    // 續體的上下文
    public val context: CoroutineContext
    // 該方法用于恢復續體的執行
    // result為掛起點執行完成的返回值,T為返回值的類型
    public fun resumeWith(result: Result<T>)
}

Continuation圖解

Kotlin續體、續體攔截器和調度器實例分析

二.ContinuationInterceptor

ContinuationInterceptor接口繼承自Element接口,是協程中的續體攔截器,代碼如下:

public interface ContinuationInterceptor : CoroutineContext.Element {
    // 攔截器的Key
    companion object Key : CoroutineContext.Key<ContinuationInterceptor>
    // 攔截器對續體進行攔截時會調用該方法,并對continuation進行緩存
    // 攔截判斷:根據傳入的continuation對象與返回的continuation對象是否相同
    public fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T>
    // 當interceptContinuation方法攔截的協程執行完畢后,會調用該方法
    public fun releaseInterceptedContinuation(continuation: Continuation<*>) {
        /* do nothing by default */
    }
    // get方法多態實現
    public override operator fun <E : CoroutineContext.Element> get(key: CoroutineContext.Key<E>): E? {
        @OptIn(ExperimentalStdlibApi::class)
        if (key is AbstractCoroutineContextKey<*, *>) {
            @Suppress("UNCHECKED_CAST")
            return if (key.isSubKey(this.key)) key.tryCast(this) as? E else null
        }
        @Suppress("UNCHECKED_CAST")
        return if (ContinuationInterceptor === key) this as E else null
    }
    // minusKey方法多態實現
    public override fun minusKey(key: CoroutineContext.Key<*>): CoroutineContext {
        @OptIn(ExperimentalStdlibApi::class)
        if (key is AbstractCoroutineContextKey<*, *>) {
            return if (key.isSubKey(this.key) && key.tryCast(this) != null) EmptyCoroutineContext else this
        }
        return if (ContinuationInterceptor === key) EmptyCoroutineContext else this
    }
}

三.CoroutineDispatcher

CoroutineDispatcher類繼承自AbstractCoroutineContextElement類,實現了ContinuationInterceptor接口,是協程調度器的基類,代碼如下:

public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
    // ContinuationInterceptor的多態實現,調度器本質上就是攔截器
    @ExperimentalStdlibApi
    public companion object Key : AbstractCoroutineContextKey<ContinuationInterceptor, CoroutineDispatcher>(
        ContinuationInterceptor,
        { it as? CoroutineDispatcher })
    // 用于判斷調度器是否要調用dispatch方法進行調度,默認為true
    public open fun isDispatchNeeded(context: CoroutineContext): Boolean = true
    // 調度的核心方法,在這里進行調度,執行block
    public abstract fun dispatch(context: CoroutineContext, block: Runnable)
    // 如果調度是由Yield方法觸發的,默認通過dispatch方法實現
    @InternalCoroutinesApi
    public open fun dispatchYield(context: CoroutineContext, block: Runnable): Unit = dispatch(context, block)
    // ContinuationInterceptor接口的方法,將續體包裹成DispatchedContinuation,并傳入當前調度器
    public final override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> =
        DispatchedContinuation(this, continuation)
    // 釋放父協程與子協程的關聯。
    @InternalCoroutinesApi
    public override fun releaseInterceptedContinuation(continuation: Continuation<*>) {
        (continuation as DispatchedContinuation<*>).reusableCancellableContinuation?.detachChild()
    }
    // 重載了"+"操作,直接返回others
    // 因為兩個調度器相加沒有意義,同一個上下文中只能有一個調度器
    // 如果需要加的是調度器對象,則直接替換成最新的,因此直接返回
    public operator fun plus(other: CoroutineDispatcher): CoroutineDispatcher = other
    override fun toString(): String = "$classSimpleName@$hexAddress"
}

四.EventLoop

EventLoop類繼承自CoroutineDispatcher類,用于協程中任務的分發執行,只在runBlocking方法中和Dispatchers.Unconfined調度器中使用。與Handler中的Looper類似,在創建后會存儲在當前線程的ThreadLocal中。EventLoop本身不支持延時執行任務,如果需要可以自行繼承EventLoop并實現Delay接口,EventLoop中預留了一部分變量和方法用于延時需求的擴展。

為什么協程需要EventLoop呢?協程的本質是續體傳遞,而續體傳遞的本質是回調,假設在Dispatchers.Unconfined調度下,要連續執行多個suspend方法,就會有多個續體傳遞,假設suspend方法達到一定數量后,就會造成StackOverflow,進而引起崩潰。同樣的,我們知道調用runBlocking會阻塞當前線程,而runBlocking阻塞的原理就是執行“死循環”,因此需要在循環中做任務的分發,去執行內部協程在Dispatchers.Unconfined調度器下加入的任務。

EventLoop代碼如下:

internal abstract class EventLoop : CoroutineDispatcher() {
    // 用于記錄使用當前EventLoop的runBlocking方法和Dispatchers.Unconfined調度器的數量
    private var useCount = 0L
    // 表示當前的EventLoop是否被暴露給其他的線程
    // runBlocking會將EventLoop暴露給其他線程
    // 因此,當runBlocking使用時,shared必須為true
    private var shared = false
    // Dispatchers.Unconfined調度器的任務執行隊列
    private var unconfinedQueue: ArrayQueue<DispatchedTask<*>>? = null
    // 處理任務隊列的下一個任務,該方法只能在EventLoop所在的線程調用
    // 返回值<=0,說明立刻執行下一個任務
    // 返回值>0,說明等待這段時間后,執行下一個任務
    // 返回值為Long.MAX_VALUE,說明隊列里沒有任務了 
    public open fun processNextEvent(): Long {
        if (!processUnconfinedEvent()) return Long.MAX_VALUE
        return 0
    }
    // 隊列是否為空
    protected open val isEmpty: Boolean get() = isUnconfinedQueueEmpty
    // 下一個任務多長時間后執行
    protected open val nextTime: Long
        get() {
            val queue = unconfinedQueue ?: return Long.MAX_VALUE
            return if (queue.isEmpty) Long.MAX_VALUE else 0L
        }
    // 任務的核心處理方法
    public fun processUnconfinedEvent(): Boolean {
        // 若隊列為空,則返回
        val queue = unconfinedQueue ?: return false
        // 從隊首取出一個任務,如果為空,則返回
        val task = queue.removeFirstOrNull() ?: return false
        // 執行
        task.run()
        return true
    }
    // 表示當前EventLoop是否可以在協程上下文中被調用
    // EventLoop本質上也是協程上下文
    // 如果EventLoop在runBlocking方法中使用,必須返回true
    public open fun shouldBeProcessedFromContext(): Boolean = false
    // 向隊列中添加一個任務
    public fun dispatchUnconfined(task: DispatchedTask<*>) {
        // 若隊列為空,則創建一個新的隊列
        val queue = unconfinedQueue ?:
            ArrayQueue<DispatchedTask<*>>().also { unconfinedQueue = it }
        queue.addLast(task)
    }
    // EventLoop當前是否還在被使用
    public val isActive: Boolean
        get() = useCount > 0
    // EventLoop當前是否還在被Unconfined調度器使用
    public val isUnconfinedLoopActive: Boolean
        get() = useCount >= delta(unconfined = true)
    // 判斷隊列是否為空
    public val isUnconfinedQueueEmpty: Boolean
        get() = unconfinedQueue?.isEmpty ?: true
    // 下面三個方法用于計算使用當前的EventLoop的runBlocking方法和Unconfined調度器的數量
    // useCount是一個64位的數,
    // 它的高32位用于記錄Unconfined調度器的數量,低32位用于記錄runBlocking方法的數量
    private fun delta(unconfined: Boolean) =
        if (unconfined) (1L shl 32) else 1L
    fun incrementUseCount(unconfined: Boolean = false) {
        useCount += delta(unconfined)
        // runBlocking中使用,shared為true
        if (!unconfined) shared = true 
    }
    fun decrementUseCount(unconfined: Boolean = false) {
        useCount -= delta(unconfined)
        // 如果EventLoop還在被使用
        if (useCount > 0) return
        assert { useCount == 0L }
        // 如果EventLoop不被使用了,并且在EventLoop中使用過
        if (shared) {
            // 關閉相關資源,并在ThreadLocal中移除
            shutdown()
        }
    }
    protected open fun shutdown() {}
}

協程中提供了EventLoopImplBase類,間接繼承自EventLoop,實現了Delay接口,用來延時執行任務。同時,協程中還提供單例對象ThreadLocalEventLoop用于EventLoop在ThreadLocal中的存儲。

“Kotlin續體、續體攔截器和調度器實例分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

富宁县| 南江县| 泸西县| 格尔木市| 龙泉市| 潮安县| 扶沟县| 隆化县| 台北市| 合山市| 黄浦区| 河池市| 双辽市| 鹤峰县| 鄂伦春自治旗| 宁武县| 新郑市| 元氏县| 大丰市| 都匀市| 晋城| 遂川县| 云梦县| 广平县| 吴江市| 英山县| 城市| 永济市| 绵阳市| 长子县| 海门市| 南昌市| 宝鸡市| 鹤峰县| 澜沧| 二手房| 高唐县| 北辰区| 光泽县| 饶阳县| 宜章县|