具有延续性的 Swift Actor 线程安全性

问题描述 投票:0回答:1

我正在阅读有关参与者的内容,作为一个教学示例,我正在重写一段旧代码,该代码使用委托来使用异步等待。我正在使用已检查的延续来将同步连接到异步。

我读了这篇介绍:https://www.swiftbysundell.com/articles/swift-actors/据我了解,由于演员是可重入的,我们需要跟踪当前正在执行的工作 - 即活动任务。

我不确定这如何与延续结合在一起。

这是我的代码。感谢您的帮助!

public actor MyNewDelegateSub {
    
    
    private var activeTask: Task<BLEDevice, Error>?
    private var checkedThrowingContinuation: CheckedContinuation<BLEDevice, Error>?
    private var bleDelegate: BluetoothLEDelegate
    
    
    public func returnFunctionThatReplacesDelegateCallbacks() async throws -> BLEDevice? {
        if let existingTask = activeTask {
            return try await existingTask.value
        }
        
        let task = Task<BLEDevice?, Error> {
            return try await withCheckedThrowingContinuation({ [weak self] (continuation: CheckedContinuation<BLEDevice, Error>) in
                bleDelegate.checkedThrowingContinuation = continuation
                do{
                    bleDelegate.scan()
                    activeTask = nil
                } catch {
                   activeTask = nil
                   throw error
            })
        }
        activeTask = task
        return try await task.value
    }
}

private final class BluetoothLEDelegate: NSObject, CBCentralManagerDelegate {
    
    private let centralManager = CBCentralManager()
    var checkedThrowingContinuation: CheckedContinuation<BLEDevice, Error>?
    
    init() {
        centralManager.delegate = self
    }
    
    
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        checkedThrowingContinuation?.resume(returning: BLEDevice(peripheral) )
        checkedThrowingContinuation = nil
       }
    ....
}
swift async-await concurrency actor
1个回答
0
投票

是的,在

withCheckedThrowingContinuation
中使用
Task
是完全可以接受的。


话虽如此,但此代码片段存在很多问题:

  1. 在你的

    do
    -
    try
    -
    catch
    中,没有
    try
    。因此,永远没有什么
    catch
    。另外,你不会从
    throw
    内部
    withCheckedThrowingContinuation
    ,无论如何,你会
    resume
    出现错误。

  2. 每当您使用非结构化并发时,例如

    Task {…}
    ,您都有责任编写自己的取消处理代码,例如
    withTaskCancellationHandler

  3. 在更风格化的观察中,我可能会建议,而不是将延续传递给蓝牙管理器对象(它将这两种类型纠缠在一起,引入关于延续的非本地推理,这实际上会导致其最终误用等)你将这两种类型解耦:

    • 赋予与相关委托方法关联的蓝牙管理器对象闭包属性,并让委托方法调用这些闭包……现在蓝牙管理器不再与延续代码紧密耦合;和

    • withCheckedThrowingContinuation
      内,启动蓝牙管理器,设置其闭包,并在这些闭包内,
      resume
      并根据需要进行清理。

  4. 发现蓝牙设备的正确模式可能是

    AsyncSequence
    ,例如,
    AsyncStream
    ,无论如何,这不是一个任务。请观看 WWDC 2021 视频认识 AsyncSequence

© www.soinside.com 2019 - 2024. All rights reserved.