【问题标题】:Can't set AsyncStream `onTermination` handler无法设置 AsyncStream `onTermination` 处理程序
【发布时间】:2021-11-01 23:03:15
【问题描述】:

有没有人成功地创建了一个 AsyncStream 并设置了它的 onTermination 处理程序?我做不到。以下内容是直接从提案 (https://github.com/apple/swift-evolution/blob/main/proposals/0314-async-stream.md) 复制和粘贴的,除了我通过将 detach 现代化为 Task.detached 来摆脱警告:

    let t = Task.detached {
      func make123Stream() -> AsyncStream<Int> {
        AsyncStream { continuation in
          continuation.onTermination = { termination in
            switch termination {
            case .finished:
                print("Regular finish")
            case .cancelled:
                print("Cancellation")
            }
          }
            Task.detached {
            for n in 1...3 {
              continuation.yield(n)
              sleep(2)
            }
            continuation.finish()
          }
        }
      }

      for await n in make123Stream() {
        print("for-in: \(n)")
      }
      print("After")
    }
    sleep(3)
    t.cancel()

看起来不错,但它不能编译,而且我找不到让它编译的方法。 onTermination setter 上的错误消息如下:

 Converting non-concurrent function value to 
 '@Sendable (AsyncStream<Int>.Continuation.Termination) -> Void' 
 may introduce data races

我不知道编译器要我做什么。有没有人解决这个问题,解决办法是什么?

(我已经为此提交了一个错误。)

【问题讨论】:

    标签: swift async-await swift5.5 swift-concurrency


    【解决方案1】:

    更新:

    您可以通过添加@Sendable 作为闭包内的第一件事来解决此错误(在捕获列表、参数和in 关键字之前),例如:

    continuation.onTermination = { @Sendable termination in
        switch termination {
        case .finished:
            print("Regular finish")
        case .cancelled:
            print("Cancellation")
        @unknown default:
            break
        }
    }
    

    原答案:

    是的,我猜这是一个错误,因为我能够通过添加来编译它:

    as (@Sendable (AsyncStream<Int>.Continuation.Termination) -> Void)
    

    关闭后,如:

    continuation.onTermination = { termination in
        switch termination {
        case .finished:
            print("Regular finish")
        case .cancelled:
            print("Cancellation")
        @unknown default:
            break
        }
    } as (@Sendable (AsyncStream<Int>.Continuation.Termination) -> Void)
    

    (我还添加了 @unknown default 案例以消除出现的新警告。)

    【讨论】:

    • 是的,这很奇怪——就像编译器无法将闭包转换为 @Sendable 或其他东西一样。 ?‍♂️
    • 我们知道 Sendable 通常存在问题,所以这可能是他们正在处理的问题。无论如何,你的解决方法让我可以做我想做的事,所以这就结束了!
    • 感谢您更新解决方法;我从 Doug Gregor 那里得到了同样的通知,正准备在这里给你发消息。 :)
    • @matt 哈哈,没问题! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    • 2022-08-19
    • 1970-01-01
    • 2021-01-29
    • 2012-01-07
    • 1970-01-01
    相关资源
    最近更新 更多