让同步数据源与异步流程更好地协作

152 阅读1分钟
extension Sequence {

  /// An asynchronous sequence containing the same elements as this sequence,
  /// but on which operations, such as `map` and `filter`, are implemented asynchronously.
  @inlinable
  public var async: AsyncSyncSequence<Self> {
    AsyncSyncSequence(self)
  }
}

/// An asynchronous sequence composed from a synchronous sequence.
/// 
/// Asynchronous lazy sequences can be used to interface existing or pre-calculated
/// data to interoperate with other asynchronous sequences and algorithms based on
/// asynchronous sequences.
/// 
/// This functions similarly to `LazySequence` by accessing elements sequentially
/// in the iterator's `next()` method.
@frozen
public struct AsyncSyncSequence<Base: Sequence>: AsyncSequence {

  public typealias Element = Base.Element

  @frozen
  public struct Iterator: AsyncIteratorProtocol {

    @usableFromInline
    var iterator: Base.Iterator?

    @usableFromInline
    init(_ iterator: Base.Iterator) {
      self.iterator = iterator
    }

    @inlinable
    public mutating func next() async -> Base.Element? {
      if !Task.isCancelled, let value = iterator?.next() {
        return value
      } else {
        iterator = nil
        return nil
      }
    }
  }

  @usableFromInline
  let base: Base

  @usableFromInline
  init(_ base: Base) {
    self.base = base
  }

  @inlinable
  public func makeAsyncIterator() -> Iterator {
    Iterator(base.makeIterator())
  }
}

extension AsyncSyncSequence: Sendable where Base: Sendable { }

举例说明:

import Foundation

// 假设有一批待检测的域名
let domainList = ["example1.com", "example2.com", "usable-domain.com", "example3.com"]

// 模拟一个异步函数,用来检查单个域名是否可用
func checkDomainAvailability(_ domain: String) async -> Bool {
    // 模拟网络请求的延迟
    try? await Task.sleep(nanoseconds: 500_000_000) // 0.5秒延迟
    // 假设域名以 "usable" 开头的是可用的
    return domain.hasPrefix("usable")
}

// 扩展:使 Sequence 可以通过 `async` 属性生成异步序列
extension Sequence {
    var async: AsyncSyncSequence<Self> {
        AsyncSyncSequence(self)
    }
}

// 异步检查域名的可用性
Task {
    for await domain in domainList.async {
        if await checkDomainAvailability(domain) {
            print("\(domain) 是第一个可用的域名")
            break  // 找到第一个可用域名后立即停止
        } else {
            print("\(domain) 不可用")
        }
    }
}
  1. for await 循环:逐个异步遍历 domainList 中的域名。

  2. await checkDomainAvailability(domain):异步检查域名的可用性。

  3. break:在找到第一个可用域名后,立即退出循环,不再继续检查剩余的域名。