简体   繁体   English

Swift `await` 执行后任务和等待/异步队列?

[英]Swift task and await/async queue after `await` execution?

I am trying to understand what the rule is when calling Task {... } and, in that task, calling await in terms of threads.我试图了解调用Task {... }时的规则是什么,并且在该任务中,根据线程调用await

This example works:这个例子有效:

struct TaskTestView: View {
    
    let url = URL(string: "https://www.google.com")!
    @State private var message = "Loading..."

    var body: some View {
        Text(message)
            .task {
                /// on MAIN THREAD
                do {
                    var receivedLines = [String]()
                    for try await line in url.lines {
                 /// on MAIN THREAD
                        receivedLines.append(line)
                        message = "Received \(receivedLines.count) lines"
                    }
                } catch {
                    message = "Failed to load"
                }
            }
    }
}

This does not:这不会:

struct TaskTestView: View {

    @StateObject var model = TaskTestViewModel()
    
    var body: some View {
        Text(model.message)
            .task {
                /// - here it is on main thread
                await model.refresh()
                /// - here it is NOT on main thread
                print("after refresh: on main?")
            }
    }
}

class TaskTestViewModel:ObservableObject {
    
    let url = URL(string: "https://www.google.com")!
    @Published private(set) var message = "Loading..."
    
    func refresh() async {
        
        do {
            var receivedLines = [String]() // on main thread
            for try await line in url.lines {
                receivedLines.append(line) // NOT on main thread
                message = "Received \(receivedLines.count) lines"
            }
        } catch {
            message = "Failed to load"
        }
        
    }
    
}
  1. Why does the code run on the main thread after line for try await line in url.lines { in the first example?为什么代码在第一个示例中的for try await line in url.lines {之后在主线程上运行?
  2. Why does the code NOT run on the main thread after that same line but in the second example?为什么代码不在同一行之后但在第二个示例中的主线程上运行?

How would I know the answer to those questions without running the code and putting a breakpoint to inspect the thread I am on?如果不运行代码并设置断点来检查我所在的线程,我怎么知道这些问题的答案呢?

Obviously the main issue here is that I want to make sure I update @State variables on main so the view works properly, but, not having this concept clear makes it hard to design proper patterns.显然,这里的主要问题是我想确保更新 main 上的 @State 变量,以便视图正常工作,但是,如果这个概念不明确,就很难设计出合适的模式。

There are not clear rules regarding on which thread the “continuation” will run.关于“延续”将在哪个线程上运行没有明确的规定。 WWDC 2021 video Swift concurrency: Behind the scenes talks about continuations and how the thread after the suspension point might be different than the one before. WWDC 2021 视频Swift 并发性:在幕后谈论延续以及暂停点之后的线程可能与之前的不同。

Trying to diagnose this with traditional debugging statements or breakpoints can be a frustrating exercise.尝试使用传统的调试语句或断点来对此进行诊断可能会令人沮丧。 I have encountered situations where the insertion of a few completely unrelated lines of debugging code changed the continuation threading behavior.我遇到过插入几行完全不相关的调试代码会改变连续线程行为的情况。 Bottom line, unless you tell it otherwise, it is free to decide on which thread the continuation will run and it can sometimes defy expectations.最重要的是,除非您另有说明,否则可以自由决定延续将在哪个线程上运行,并且有时可能会出乎意料。

But, if you want to make sure that your observable object updates on the main thread, you can use the @MainActor qualifier:但是,如果你想确保你的 observable object 在主线程上更新,你可以使用@MainActor限定符:

@MainActor
class TaskTestViewModel: ObservableObject {
    ... 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM