Kotlin 1.4.0-RC協程除錯

kotliner發表於2020-08-11

我們仍將重點放在1.4版本中發生的變化。在這篇部落格中,我們要介紹協程相關的幾個重要特性:

  • 協程除錯更加方便
  • 深度遞迴函式已可定義

在1.4.0-RC版本中已能體驗這些變動!

img

現在讓我們深入瞭解!

協程的除錯

協程非常適合非同步程式設計(但不僅限於此),而且已經有很多人已經或開始使用協程了。但是當使用協程編寫程式碼時,除錯將是非常痛苦的事。協程線上程之間切換。可能難以理解指定協程的功能或監控其上下文。在某些情況下,無法跟蹤斷點上的step。這導致必須依靠日誌記錄或消耗精力來使用協程除錯程式碼。為了解決這個問題,我們在Kotlin外掛中引入了新功能,以便於協程的除錯。

*Debug Tool Window 現在包含一個新的 Coroutines *選項卡。預設情況下它是顯示的,你可以顯示和隱藏它:

在該選項卡,你可以看到當前在執行和已暫停協程的相關資訊。協程由執行它們的排程器進行分組。如果啟動協程時給予自定義名稱,則可以在工具視窗中找到這個名稱。在下面的示例中,可以看到主協程正在執行(已在斷點處停止),而其他四個協程已掛起:

新功能讓你可以檢查每個協程的狀態並檢視區域性變數和被捕獲變數的值。這同樣適用於已掛起的協程!

在該示例中,我們檢查了已掛起協程區域性變數的值:

選擇一個被掛起的協程(點選invokeSuspend以檢視其狀態),Variables選項卡將顯示區域性變數的狀態:

img

現在你可以看到完整的協程建立堆疊以及協程內部的呼叫堆疊:

通過Get Coroutines Dump可獲取包含每個協程及其堆疊狀態的完整報告:

目前,協程轉儲檔案比較簡單,但我們將在後續版本增強其可讀性,提升其作用。

請注意,要使偵錯程式在協程內部的指定斷點處停止,需要對該斷點勾選Suspend: All選項:

若要嘗試這個除錯協程的新功能,你需要使用最新版本的kotlinx.coroutines1.3.8-1.4.0-rc,以及最新版本的Kotlin外掛)(例如1.4.0-rc-release-IJ2020.1 -2)。

該功能只適用於Kotlin/JVM。如果你遇到任何問題(請不要忘記與我們分享詳細資訊!),可以開啟Build, Execution, Deployment | Debugger | Data Views | Kotlin中的Preferences,選擇Disable coroutines agent以關閉它。目前,我們正在釋出該功能,以便能在實驗狀態下除錯協程,我們期待你的反饋!

使用協程定義深度遞迴函式

在Kotlin 1.4中,你可以定義並執行深度大於100,000的遞迴函式,這由基於協程的標準庫提供支援。

首先讓我們看一個普通的遞迴函式,當遞迴深度過高時,其用法會導致StackOverflowError。之後,我們將討論如何處理該問題並使用Kotlin標準庫重寫功能。

我們將使用一個簡單的二叉樹,其中每個Tree節點都有對其leftright子節點的引用:

樹的深度,是樹的根到其最長路徑子節點的長度。可以使用以下遞迴函式進行計算:

樹的深度是左右子節點的深度最大值加一。樹無子節點時為零。

當遞迴深度較小時,該函式能正常執行:

但如果建立的樹深度大於100,000,這在實際場景中並不少見,那麼你將得到StackOverflowError

根源是呼叫棧變得過大了。要解決該問題,可以通過VM配置來增加最大棧大小。但是這隻適用於特定的場景,通常情況下並不是一個可行的解決方案。

另外,你還可以重寫程式碼,手動將過程中的結果存在堆中而不是棧中。這個解決方案在大多數情況下都有用,並且在其他語言中很常見。但是最後程式碼會變得複雜且難以理解,忘記了簡潔優雅的初衷。你可以在這裡找到示例。

基於協程的機制,現在Kotlin提供了一種解決該問題的精巧方案。

Kotlin庫現在包含DeepRecursiveFunction定義,這個定義通過掛起機制對遞迴呼叫進行建模:

你可以比較兩個版本,最初的版本和使用了DeepRecursiveFunction的版本,以確保邏輯不變。現在你的新函式變成了型別為DeepRecursiveFunction的變數,你可以通過‘invoke’協議作為depthFunction(t)進行呼叫。現在,函式體成為DeepRecursiveFunction的lambda引數主體,並且遞迴呼叫已替換為callRecursive。這些改動非常簡單直接。請注意,雖然新的depth函式在背後使用了協程,但它本身並不是suspend函式。

瞭解DeepRecursiveFunction的實現方式很有意思,但是不瞭解亦不阻礙你的使用,並從中獲得收益。可以在這篇部落格中瞭解實現的詳細資訊。

DeepRecursiveFunction是Kotlin標準庫的一部分,而不是kotlinx.coroutines庫的一部分,因為它與非同步程式設計無關。目前該API仍處於實驗階段,我們期待你的反饋!

如何嘗試

同樣,你可以在 play.kotl.in線上使用Kotlin

IntelliJ IDEA,你可以更新Kotlin外掛到1.4.0-RC版本。操作指南

如果要在預覽版安裝之前建立的專案中使用,則需要在Gradle或Maven中針對預覽版配置構建指令碼。請注意,與以前的預覽版不同,Kotlin 1.4.0-RC可直接通過Maven Central獲取。這意味著你無需手動將kotlin-eap儲存庫新增到構建檔案中。

你可以在Github發行頁下載命令列編譯器

分享你的反饋

如果你發現錯誤並向我們的問題跟蹤器進行報告,我們表示非常感謝。我們嘗試在最終發行版前解決所有重要問題,這意味著無需等到下一個Kotlin發行版你的問題便能得到解決。

如果你有任何疑問並想參與討論,歡迎加入Kotlin Slack(在這裡獲得邀請)的#eap channel頻道。在該頻道中,你還可以獲取有關新預覽版的通知。

Let’s Kotlin!

相關文章