Swift async let 取消不起作用
Swift async let cancellation doesn't work
我对被取消的任务有点困惑。
概览:
checkCancellation
函数有 2 个子任务,一个任务 运行s computeA
和另一个 computeB
。他们运行并发,computeB
抛出错误。
疑问:
- 我希望子任务
computeA
被取消,因为 computeB
抛出了一个错误,但 computeA
从未被取消。
- 是我的理解有误还是遗漏了什么?
- 或者这是一个错误?
注:
- 我正在使用
SwiftUI
项目(因为 Swift 游乐场不支持 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
疑问:
我仍然不确定我是否理解原始代码中出现这种行为的原因
I expected child task computeA to be cancelled because computeB threw an error, but computeA was never cancelled. Is my understanding wrong or am I missing something?
是的,是的。你的理解有误,你漏掉了什么。
视频中的评论与在任务组中创建的子任务有关。实际发生的情况是,当错误从 child 任务渗透到任务组时,任务组会在所有其他 child 任务上调用 cancel
。
但是你正在使用async let
进行测试。没有任务组。所以没有人“在那里”取消另一个子任务。事实上,如果你仔细观看视频,你会发现它正确地告诉了你预期的内容:
如果取消parent个任务,child个任务也会自动取消。
如果 async let
任务在第二个 async let
任务甚至初始化之前抛出,则第二个任务“出生取消”。 还在等待(这个视频说的很清楚,没错);如果它没有通过中止响应取消,它将继续完成。
这里的重点是parent任务必须有条不紊地结束。在它的 children 以某种方式完成之前,它不会结束。 (同样,视频对此非常清楚。)如果这意味着自动等待任务完成而不管抛出,那么就会发生这种情况。
另一个需要注意的有趣的事情是,使用 async let
,你稍后说 try await
,如果子任务抛出,你甚至不会听到它(并且什么都不会发生这方面),直到你到达 try await
发生的地步。换句话说,throw 只能渗透到你实际说 try
的地方;没有其他意义。
我对被取消的任务有点困惑。
概览:
checkCancellation
函数有 2 个子任务,一个任务 运行scomputeA
和另一个computeB
。他们运行并发,computeB
抛出错误。
疑问:
- 我希望子任务
computeA
被取消,因为computeB
抛出了一个错误,但computeA
从未被取消。 - 是我的理解有误还是遗漏了什么?
- 或者这是一个错误?
注:
- 我正在使用
SwiftUI
项目(因为 Swift 游乐场不支持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
疑问:
我仍然不确定我是否理解原始代码中出现这种行为的原因
I expected child task computeA to be cancelled because computeB threw an error, but computeA was never cancelled. Is my understanding wrong or am I missing something?
是的,是的。你的理解有误,你漏掉了什么。
视频中的评论与在任务组中创建的子任务有关。实际发生的情况是,当错误从 child 任务渗透到任务组时,任务组会在所有其他 child 任务上调用 cancel
。
但是你正在使用async let
进行测试。没有任务组。所以没有人“在那里”取消另一个子任务。事实上,如果你仔细观看视频,你会发现它正确地告诉了你预期的内容:
如果取消parent个任务,child个任务也会自动取消。
如果
async let
任务在第二个async let
任务甚至初始化之前抛出,则第二个任务“出生取消”。 还在等待(这个视频说的很清楚,没错);如果它没有通过中止响应取消,它将继续完成。
这里的重点是parent任务必须有条不紊地结束。在它的 children 以某种方式完成之前,它不会结束。 (同样,视频对此非常清楚。)如果这意味着自动等待任务完成而不管抛出,那么就会发生这种情况。
另一个需要注意的有趣的事情是,使用 async let
,你稍后说 try await
,如果子任务抛出,你甚至不会听到它(并且什么都不会发生这方面),直到你到达 try await
发生的地步。换句话说,throw 只能渗透到你实际说 try
的地方;没有其他意义。