【发布时间】:2021-10-24 06:30:19
【问题描述】:
我对被取消的任务感到有些困惑。
概述:
-
checkCancellation函数有 2 个子任务,一个任务运行computeA,另一个运行computeB。它们同时运行,computeB会抛出错误。
怀疑:
- 我预计子任务
computeA会被取消,因为computeB抛出错误,但computeA从未被取消。 - 是我的理解有误还是我遗漏了什么?
- 或者这是一个错误?
注意:
- 我正在使用
SwiftUI项目(因为 Swift Playgrounds 不支持async let) macOS Big Sur 11.5.2 (20G95)Xcode Version 13.0 beta 5 (13A5212g)
输出:
A - started
B - going to throw
A - going to return, Task.isCancelled = false
error: infinity
并发函数定义:
import Foundation
import UIKit
enum ComputationError: Error {
case infinity
}
fileprivate func computeA() async throws -> Int {
print("A - started")
await Task.sleep(2 * 100_000_000)
print("A - going to return, Task.isCancelled = \(Task.isCancelled)") //I expected Task.isCancelled to be true
return 25
}
fileprivate func computeB() async throws -> Int {
print("B - going to throw")
throw ComputationError.infinity
}
func checkCancellation() async throws {
async let a = computeA()
async let b = computeB()
let c = try await a + b
print("c = \(c)")
}
调用并发函数
struct ContentView: View {
var body: some View {
Button("check cancellation") {
Task {
do {
try await checkCancellation()
print("normal exit")
} catch {
print("error: \(error)")
}
}
}
}
}
观察:
- 当我将代码更改为
let c = try await b + a
输出:
A - started
B - going to throw
A - going to return, Task.isCancelled = true
error: infinity
怀疑:
我仍然不确定我是否理解原始代码中这种行为的原因
【问题讨论】:
-
检查取消是任务的责任。您的“睡眠”不是“可取消的”,这意味着它不会检查任何“取消点”,因此它将一直运行到完成。请阅读Task Cancellation。 ;)
-
另外,请注意在调用静态任务函数时,例如
Task.isCancelled,您检查执行此语句的任务,即:Task { ...; print(Task.isCancelled) } -
@CouchDeveloper 我同意由实现来检查取消并采取适当的措施,但是我的问题是为什么
Task.isCancelled = false在输出中即使computeB抛出错误,理想情况下它应该有使正在进行的子任务被标记为已取消,这不会发生 -
@CouchDeveloper 根据developer.apple.com/videos/play/wwdc2021/10134,一旦其中一个子任务抛出错误,就会导致其他子任务被标记为已取消。在我的情况下,另一个子任务没有被标记为已取消。那是疑问/问题
标签: swift async-await concurrency swift-concurrency