Swift AsyncSequence — 代碼實例詳解
前言
AsyncSequence 是并發性框架和SE-298[1] 提案的一部分。它的名字意味著它是一個提供異步、順序和迭代訪問其元素的類型。換句話說:它是我們在 Swift 中熟悉的常規序列的一個異步變體。
就像你不會經常創建你的自定義序列一樣,我不期望你經常創建一個自定義的 AsyncSequence 實現。然而,由于與 AsyncThrowingStream和AsyncStream 等類型一起使用,你很可能不得不與異步序列一起工作。因此,我將指導你使用 AsyncSequence 實例進行工作。
什么是 AsyncSequence?
AsyncSequence 是我們在Swift中熟悉的 Sequence 的一個異步變體。由于它的異步性,我們需要使用 await 關鍵字,因為我們要處理的是異步定義的方法。如果你沒有使用過 async/await,我鼓勵你閱讀我的文章:Swift 中的async/await ——代碼實例詳解
值可以隨著時間的推移而變得可用,這意味著一個 AsyncSequence 在你第一次使用它時可能不包含也可能包含一些,或者全部的值。
重要的是要理解 AsyncSequence 只是一個協議。它定義了如何訪問值,但并不產生或包含值。AsyncSequence 協議的實現者提供了一個 AsyncIterator,并負責開發和潛在地存儲值。
創建 AsyncSequence
創建一個自定義的 AsyncSequence。
為了更好地理解 AsyncSequence 是如何工作的,我將演示一個實現實例。然而,在定義你的 AsyncSequence 的自定義實現時,你可能想用 AsyncStream 來代替,因為它的設置更方便。因此,這只是一個代碼例子,以更好地理解 AsyncSequence 的工作原理。
下面的例子沿用了原始提案中的例子,實現了一個計數器。這些值可以立即使用,所以對異步序列沒有太大的需求。然而,它確實展示了一個異步序列的基本結構:
如您所見,我們定義了一個實現 AsyncSequence 協議的 Counter 結構體。該協議要求我們返回一個自定義的 AsyncIterator,我們使用內部類型解決了這個問題。我們可以決定重寫此示例以消除對內部類型的需求:
我們現在可以將 self 作為迭代器返回,并保持所有邏輯的集中。
注意,我們必須通過提供 typealias 來幫助編譯器遵守 AsyncSequence 協議。
next() 方法負責對整體數值進行迭代。我們的例子歸結為提供盡可能多的計數值,直到我們達到極限。我們通過對 Task.isCancelled 的檢查來實現取消支持。
異步序列的迭代
現在我們知道了什么是 AsyncSequence 以及它是如何實現的,現在是時候開始迭代這些值了。
以上述例子為例,我們可以使用 Counter 開始迭代:
我們必須使用 await 關鍵字,因為我們可能會異步接收數值。一旦不再有預期的值,我們就退出for循環。異步序列的實現者可以通過在 next() 方法中返回 nil 來表示達到極限。在我們的例子中,一旦計數器達到配置的極限,或者迭代取消,我們就會達到這個預期:
許多常規的序列操作符也可用于異步序列。其結果是,我們可以以異步的方式執行映射和過濾等操作。
例如,我們可以只對偶數進行過濾:
或者我們可以在迭代之前將計數映射為一個 String :
我們甚至可以使用 AsyncSequence 而不使用for循環,通過使用 contains 等方法。
注意,上述方法是異步的,意味著它有可能無休止地等待一個值的存在,直到底層的 AsyncSequence 完成。
結論
AsyncSequence 是我們在Swift中熟悉的常規 Sequence 的異步替代品。就像你不會經常自己創建一個自定義 Sequence 一樣,你也不太可能創建自定義的異步序列。
參考資料
[1]SE-298: https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md