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提高了灵活性,但是对于动态任务组表达比较繁琐,比较适合处理固定数量的异步任务
相关推荐
懋学的前端攻城狮21 小时前
数据持久化与缓存策略:在离线与在线间架起桥梁
ios·swift
2501_915918411 天前
使用快蝎IDE进行iOS开发:从项目创建到真机调试全流程
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
大熊猫侯佩3 天前
别被系统绑架:SwiftUI List 替换背后的底层逻辑
swiftui·swift·apple
花间相见3 天前
【MS-Swift实战】:LoRA原理+核心参数(r/alpha)调参指南(适配Qwen-1.8B医疗场景)
开发语言·r语言·swift
2501_915918413 天前
快蝎iOS开发IDE:免Xcode开发,支持Swift/Flutter项目
ide·vscode·ios·个人开发·xcode·swift·敏捷流程
我现在不喜欢coding4 天前
Swift 核心协议揭秘:从 Sequence 到 Collection,你离标准库设计者只差这一步
ios·swift
2501_915909064 天前
Xcode从入门到精通:全面解析iOS开发IDE的核心功能与实际应用指南
ide·vscode·ios·个人开发·xcode·swift·敏捷流程
东坡肘子4 天前
从 OpenSwiftUI 到 DanceUI:换个方式 Dive SwiftUI -- 肘子的 Swift 周报 #132
人工智能·swiftui·swift
visual_zhang5 天前
Swift 方法派发机制深度解析 —— 兼与 Objective-C `objc_msgSend` 对比
objective-c·swift
用户79457223954135 天前
【SwiftyJSON】拯救你的 as? [String: Any]——链式 JSON 访问的正确姿势
swiftui·objective-c·swift