我很好奇为什么Task C和Task D不在主线程上执行,与Task A和Task B不同。我理解任务从其父级继承上下文,在这种情况下,它们都共享同一个父级。是否可以假设调用函数会导致创建detached任务?
struct ThreadTestView: View {
var body: some View {
Text("Test Thread")
.onAppear {
// Task A
print("Task A - \(threadInfo())")
// Task B
Task {
print("Task B - \(threadInfo())")
}
// Task C
printInfo("Task C")
// Task D
Task {
printInfo("Task D")
}
}
}
func printInfo(_ source: String) {
Task {
print("\(source) - \(threadInfo())")
}
// detached
Task.detached {
print("\(source) - detached \(threadInfo())")
}
}
func threadInfo() -> String {
"isMain:\(Thread.isMainThread) - \(Thread.current)"
}
}
#Preview {
ThreadTestView()
}
控制台输出:
Task A - isMain:true - <_NSMainThread: 0x280694040>{number = 1, name = main}
Task C - isMain:false - <NSThread: 0x2806c6b00>{number = 8, name = (null)}
Task C - detached isMain:false - <NSThread: 0x2806c4580>{number = 5, name = (null)}
Task B - isMain:true - <_NSMainThread: 0x280694040>{number = 1, name = main}
Task D - isMain:false - <NSThread: 0x2806c6b00>{number = 8, name = (null)}
Task D - detached isMain:false - <NSThread: 0x2806c6b00>{number = 8, name = (null)}
巨大的免责声明:我仍在填补自己对 Swift Concurrency 理解的空白,因此我很高兴以下任何陈述被证明是错误的。
我认为这里重要的一点是“主线”与“主角”不是一回事。两者之间存在一些差异,但一个显着的差异是参与者是一种编译时构造,而线程主要是一种运行时构造。仅仅因为代码在主线程上运行并不意味着它是“主要参与者隔离的”。查看 onAppear(perform:) 方法的文档,您可以看到
perform
闭包不包含 @MainActor
注释,因此它不是主要参与者隔离的,尽管我们可以非常有信心它将在主线程上调用。因此,当您从该闭包内部实例化 Task
时(尽管 Task.init
继承了当前 actor),闭包本身并不是与 actor 隔离的,因此没有可以继承的 actor。执行器可以自由地将此任务安排在协作线程池中可用的任何线程上,甚至可以安排在主线程上。尝试用 printInfo
注释您的 @MainActor
函数,看看情况如何变化。