0%

【文章翻譯】Dart asynchronous programming: Isolates and event loops

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

Dart 非同步程式設計:Isolate 和事件迴圈

Dart 儘管是單執行緒語言,但它支援 futures、streams、背景工作以及你在現代非同步和(在 Flutter 的情況下)反應式編寫程式碼所需的所有其他功能。本文涵蓋 Dart 支援背景工作的基礎:isolate事件迴圈

如果您更喜歡透過觀看或聆聽來學習,本文中的所有內容都包含在以下影片中,該影片是 Flutter in Focus 影片系列 Dart 中的非同步程式設計 的一部分:

還在這裡嗎?讓我們來談談 isolate。

Isolate

Isolate 是所有 Dart 程式碼執行的環境。它就像機器上的一個小空間,擁有自己的私有記憶體區塊和一個運行事件迴圈的單執行緒。

一個 isolate 擁有自己的記憶體和一個運行事件迴圈的單執行緒。

在許多其他語言(如 C++)中,您可以讓多個執行緒共用相同的記憶體並執行您想要的任何程式碼。然而,在 Dart 中,每個執行緒都在其自己的 isolate 中,擁有自己的記憶體,並且該執行緒僅處理事件(稍後會詳細介紹)。

許多 Dart 應用程式在其單個 isolate 中運行所有程式碼,但如果需要,您可以擁有多個 isolate。如果您要執行的計算量非常大,以至於如果在主 isolate 中運行它可能會導致掉幀,那麼您可以使用 Isolate.spawn()Flutter 的 compute() 函數。這兩個函數都會建立一個單獨的 isolate 來進行數字運算,讓您的主 isolate 可以自由地(例如)重建和渲染 Widget 樹。

兩個 isolate,每個 isolate 都有自己的記憶體和執行緒。

新的 isolate 將獲得自己的事件迴圈和自己的記憶體,即使原始 isolate 是這個新 isolate 的父級,也不允許存取。這就是名稱 isolate 的來源:這些小空間彼此 隔離

事實上,isolate 合作的唯一途徑是透過來回傳遞訊息。一個 isolate 向另一個 isolate 發送訊息,接收 isolate 使用其事件迴圈處理該訊息。

Isolate 可以向其他 isolate 發送訊息。

這種缺乏共用記憶體的設計可能聽起來有點嚴格,尤其是如果您來自 Java 或 C++ 等語言,但它對 Dart 程式設計師來說有一些關鍵好處。

例如,isolate 中的記憶體分配和垃圾回收不需要鎖定。只有一個執行緒,所以如果它不忙,您就知道記憶體沒有被改變。這對於 Flutter 應用程式來說非常有用,因為它們有時需要快速地建立和銷毀大量 Widget。

事件迴圈

現在您已經對 isolate 有了基本的了解,讓我們深入了解真正使非同步程式碼成為可能的因素:事件迴圈

想像一個應用程式在其生命週期中的時間線。應用程式啟動、應用程式停止,並且在這之間會發生許多事件——來自磁碟的 I/O、來自使用者的點擊……各種各樣的事情。

您的應用程式無法預測這些事件何時發生或以何種順序發生,並且它必須使用永不阻塞的單執行緒來處理所有這些事件。因此,應用程式運行一個事件迴圈。它從其事件佇列中抓取最舊的事件,處理它,然後返回以獲取下一個事件,處理它,依此類推,直到事件佇列為空。

在應用程式運行的整個過程中——您點擊螢幕、下載內容、計時器關閉——事件迴圈只是不斷地循環,一次處理一個事件。

事件迴圈一次處理一個事件。

當動作中斷時,執行緒就會掛起,等待下一個事件。它可以觸發垃圾回收器、喝杯咖啡等等。

Dart 擁有的所有用於非同步程式設計的高階 API 和語言功能——futures、streams、async 和 await——都建立在這個簡單的迴圈之上和周圍。

例如,假設您有一個按鈕可以啟動網路請求,如下所示:

當您運行應用程式時,Flutter 會建立按鈕並將其顯示在螢幕上。然後您的應用程式等待。

您的應用程式的事件迴圈只是閒置,等待下一個事件。與按鈕無關的事件可能會進入並被處理,而按鈕則坐在那裡等待使用者點擊它。最終他們點擊了它,並且一個點擊事件進入佇列。

該事件被提取以進行處理。Flutter 查看它,渲染系統說:「這些座標與凸起的按鈕匹配」,因此 Flutter 執行 onPressed 函數。該程式碼啟動網路請求(返回一個 future)並使用 then() 方法為 future 註冊一個完成處理程式。

就這樣。迴圈完成了對該點擊事件的處理,並將其捨棄。

現在,onPressedRaisedButton 的一個屬性,網路事件使用 future 的回調函數,但這兩種技術都在做同樣的基本事情。它們都是一種告訴 Flutter 的方式:「嘿,稍後,您可能會看到特定類型的事件進入。當您看到時,請執行這段程式碼。」

因此,onPressed 正在等待點擊,future 正在等待網路資料,但從 Dart 的角度來看,這些都只是佇列中的事件。

這就是 Dart 中非同步程式碼的工作原理。Futures、streams、async 和 await——這些 API 只是您告訴 Dart 的事件迴圈:「這裡有一些程式碼,請稍後運行它」的方式。

如果我們回顧程式碼範例,您現在可以準確地看到它是如何被分解成針對特定事件的區塊的。有初始構建 (1)、點擊事件 (2) 和網路響應事件 (3)。

習慣使用非同步程式碼後,您將開始在各處識別這些模式。了解事件迴圈將有助於您繼續學習更高級別的 API。

總結

我們快速瀏覽了 isolate、事件迴圈和 Dart 中非同步程式碼的基礎。

如果您想了解更多資訊,請查看 Dart 中的非同步程式設計 系列的下一個影片。它討論了 Future API,您可以使用它來進行非同步程式設計,而無需大量程式碼。

非常感謝 Andrew Brogdon,他創作了本文所依據的影片。


Dart 非同步程式設計:Isolate 和事件迴圈 最初發佈於 Medium 上的 Dart,人們在那裡透過醒目顯示和回應這個故事來繼續對話。