Swift Task 结构化并发

结构化并发: 一种组织并发任务的编程范式,强调任务之间的明确父子关系和生命周期管理,任务形成明确的父子关系树,父任务取消会自动传播到所有子任务, 作用域结束时也会自动等待所有子任务完成

非结构化并发: 更自由的并发任务管理,需要各自管理生命周期,可以存储任务引用,更加灵活

Swift并发中,结构化并发的另种方法: task group & async let

1. TaskGroup 话不多说上代码

swift 复制代码
struct TestTaskGroup {
    func test() async {
        print("Start")
        let result = try? await withThrowingTaskGroup(of: Int.self) { group in
            for i in 0 ..< 10 {
                group.addTask(priority: .high) {
                   let result = try await calculate(i)
                    return result
                }                
            }
            print("Task added")
            for try await result in group {
                print("Get result:\(result)")
            }
            print("Task ended")
            return value
        }
        print("End")
    }
    
    private func calculate(_ value: Int) async throws -> Int {
        print("Start calculate\(value)")
        try await Task.sleep(nanoseconds: UInt64(value * 5) * NSEC_PER_SEC)
        print("任务是否被取消 \(try Task.isCancelled)")
        print("calculate\(value) done")
        return value
    }
}

log输出:

可以看到任务在调用test的时候已经开始了 并且是并发执行的,group中的每个子任务都拥有返回值,并且group子任务返回值类型是一致的这点很有限制相对于async let 这点之后会讲, 如果我们想获取到所有子任务值之后应该怎么做呢 我们来改动一下代码如图:

这里上传了图1和图2 强调一下图1这种实现是不安全的 不推荐的

如上图我们所写要求group中的返回值是统一的例子中都是Int, 另外如果任何一个子任务抛出异常 整个taskGroup都会异常,所以一定要注意单个异常的捕获 如下异常处理:

swift 复制代码
private func calculate(_ value: Int) async throws -> Int {

        print("Start calculate\(value)")

        try? await Task.sleep(nanoseconds: UInt64(value * 2) * NSEC_PER_SEC)

        if value == 2 {

            print("Work\(value) throwing error")

            throw NSError(domain: "com.example.error", code: 1, userInfo: [NSLocalizedDescriptionKey: "Task \(value) failed"])

        }

        print("calculate\(value) done")

        return value

    }
    
    func calculateTest() async {

        print("Start")

        do {

            let result = try await withThrowingTaskGroup(of: Int.self) { group in

                var value = 0

                for i in 0 ..< 3 {

                    group.addTask(priority: .high) {

                        do {

                            let result = try await calculate(i)

                            return result

                        } catch {

                            print("Error while processing results: \(error)")

                            throw error  // 重新抛出以取消整个任务组

                        }

                    }

                    

                }

                print("Task added")

                

                do {

                    for try await result in group {

                        value += result

                        

                        print("Get result:\(result) value is \(value)")

                    }

                } catch {

                    print("Error while processing results: \(error)")

                    throw error

                }

                

                print("Task ended")

                return value

            }

            print("End result is \(result)")

        } catch {

            print("Caught error: \(error)")

        }

    }

2. async let 是另外一种创建结构化并发子任务的方式,他的返回值类型不必是同样的类型,提高了灵活性

swift 复制代码
func asyncLet() async throws {
        print("Program started")
        async let result0 = calculate(0)
        async let result1 = calculate(1)  
        async let result2 = calculate(2)
        print("Tasks started concurrently")
        // 等待所有任务完成
        let (r0, r1, r2) = try await (result0, result1, result2)
        print("Program ended")

    }

从代码中可以看到,aysnc let 语法比较简洁,类似普通声明变量,只不过这里是一个异步函数,声明时立即开始并发执行,可以处理不同类型的返回值,需要明确使用try await 等待所有结果

3.两者对比:

  1. group可以动态的表达任务的数量 通过一个for循环来创建所有的任务,但是他要求所有返回值都是同一个类型
  2. asyn let提高了灵活性,但是对于动态任务组表达比较繁琐,比较适合处理固定数量的异步任务
相关推荐
初级代码游戏17 小时前
iOS开发 SwiftUI 14:ScrollView 滚动视图
ios·swiftui·swift
初级代码游戏20 小时前
iOS开发 SwitftUI 13:提示、弹窗、上下文菜单
ios·swiftui·swift·弹窗·消息框
zhyongrui1 天前
托盘删除手势与引导体验修复:滚动冲突、画布消失动画、气泡边框
ios·性能优化·swiftui·swift
zhangfeng11331 天前
CSDN星图 支持大模型微调 trl axolotl Unsloth 趋动云 LLaMA-Factory Unsloth ms-swift 模型训练
服务器·人工智能·swift
zhyongrui2 天前
SnipTrip 发热优化实战:从 60Hz 到 30Hz 的性能之旅
ios·swiftui·swift
大熊猫侯佩3 天前
Neo-Cupertino 档案:撕开 Actor 的伪装,回归 Non-Sendable 的暴力美学
swift·observable·actor·concurrency·sendable·nonsendable·data race
2501_915921434 天前
在没有源码的前提下,怎么对 Swift 做混淆,IPA 混淆
android·开发语言·ios·小程序·uni-app·iphone·swift
00后程序员张5 天前
对比 Ipa Guard 与 Swift Shield 在 iOS 应用安全处理中的使用差异
android·开发语言·ios·小程序·uni-app·iphone·swift
大熊猫侯佩5 天前
星际穿越:SwiftUI 如何让 ForEach 遍历异构数据(Heterogeneous)集合
swiftui·swift·遍历·foreach·any·异构集合·heterogeneous
hjs_deeplearning5 天前
认知篇#15:ms-swift微调中gradient_accumulation_steps和warmup_ratio等参数的意义与设置
开发语言·人工智能·机器学习·swift·vlm