You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WWDC结构化并发Kitchen Service示例存疑:任务取消逻辑困惑

关于WWDC2023《Beyond the basics of structured concurrency》中Kitchen Service示例代码的疑问解答

首先明确这段代码的实际行为:group.next()会等待任务组中第一个完成的任务,不管是厨师的轮班任务还是打烊计时器任务,只要有一个任务结束,就会立刻触发group.cancelAll()取消所有剩余任务。

你察觉到的“厨师提前完成轮班会导致提前取消所有任务”的情况,确实是这段代码的潜在问题,但要结合WWDC示例的场景设定来看:

示例场景的隐含前提

在这个Kitchen Service的演示语境中,cook.handleShift()的设计逻辑是持续运行直到任务被取消,不会主动提前结束。比如,它内部可能是一个循环处理订单、准备食材的逻辑,没有自然终止的条件——只有当任务收到取消信号时,才会退出执行。

在这个前提下,厨师的任务永远不会主动完成,第一个结束的任务必然是那个等待shiftDuration的计时器任务,这就完全符合讲师所说的“计时结束后取消所有轮班任务”的预期。

如果脱离场景设定的问题

如果handleShift()存在主动完成的可能(比如厨师提前做完所有工作后主动退出),那这段代码确实会出现逻辑问题:只要有一个厨师提前结束,就会触发所有任务被取消,不符合“到打烊时间才统一结束轮班”的需求。

调整方案(针对厨师可能主动完成的场景)

如果要确保只有打烊时间到了才取消所有任务,可以修改代码逻辑,单独等待计时器任务完成,而不是等待任意第一个任务:

func run() async throws {
    try await withThrowingTaskGroup(of: Void.self) { group in
        // 启动所有厨师的轮班任务
        for cook in staff.keys {
            group.addTask { try await cook.handleShift() }
        }

        // 单独等待打烊计时器任务,确保只有时间到了才执行取消
        try await Task.sleep(for: shiftDuration)
        
        // 取消所有轮班任务
        group.cancelAll()
        
        // 可选:等待所有任务完成,确保资源正常清理
        try await group.waitForAll()
    }
}

或者通过区分任务返回值的方式,精准等待打烊任务的完成信号:

func run() async throws {
    try await withThrowingTaskGroup(of: Bool.self) { group in
        for cook in staff.keys {
            group.addTask {
                try await cook.handleShift()
                return false // 厨师任务完成返回标识
            }
        }

        group.addTask {
            try await Task.sleep(for: shiftDuration)
            return true // 打烊任务完成返回标识
        }

        // 遍历任务结果,直到捕获到打烊信号
        for try await isClosing in group {
            if isClosing {
                group.cancelAll()
                break
            }
            // 厨师任务主动完成时,忽略并继续等待
        }
    }
}

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 18:43:39