Vla*_*kiy 8 asynchronous grand-central-dispatch async-await swift swift5
假设我有以下功能。
func first() async {
print("first")
}
func second() {
print("second")
}
func main() {
Task {
await first()
}
second()
}
main()
Run Code Online (Sandbox Code Playgroud)
尽管将first函数标记为异步没有任何意义,因为它不执行任何异步工作,但仍然有可能......
我期望即使正在等待第一个函数,它也会被异步调用。
但实际上输出是
first
second
Run Code Online (Sandbox Code Playgroud)
我如何异步调用第一个函数来模仿 GCD 的变体:
DispatchQueue.current.async { first() }
second()
Run Code Online (Sandbox Code Playgroud)
此行为将根据上下文而改变。
\n如果您从非隔离上下文调用此函数,则first和second将在单独的线程上运行。在这种情况下,second任务实际上并不是在等待first任务,而是存在一场关于哪个任务先完成的竞赛。如果您在任务中做了一些耗时的事情first,并且您会看到second任务根本不等待,就可以说明这一点。
first这引入了和之间的竞争,second并且您无法保证它们将按哪个顺序运行。(在我的测试中,它大部分时间都second在 之前运行,但偶尔仍然可以在 之前运行。)firstfirstsecond
但是,如果您从参与者隔离的上下文中调用它,则将first 在运行之前等待second屈服。
那么,问题是,您真的关心这两个任务以哪个顺序开始吗?Task { await first() }如果是这样,您可以通过(显然)在调用之后放置 来消除竞争second。或者您只是想确保secondwon\xe2\x80\x99t 等待first完成?在这种情况下,这已经是行为,不需要更改您的代码。
你问:
\n\n\n如果需要在同一队列上异步
\nawait first()运行怎么办?second()\xe2\x80\xa6 我只是想[如果它在后台线程上运行]将意味着由于 UI 更新而不是来自主线程而导致崩溃。
您可以使用 标记更新 UI 的例程@MainActor,这将使其在主线程上运行。但请注意,不要将此限定符与耗时任务本身一起使用(因为您不想阻塞主线程),而是将耗时操作与 UI 更新解耦,并将后者标记为@MainActor.
例如,下面是一个异步手动计算 \xcf\x80 并在完成后更新 UI 的示例:
\nfunc startCalculation() {\n Task {\n let pi = await calculatePi()\n updateWithResults(pi)\n }\n updateThatCalculationIsUnderway() // this really should go before the Task to eliminate any races, but just to illustrate that this second routine really does not wait\n}\n\n// deliberately inefficient calculation of pi\n\nfunc calculatePi() async -> Double {\n await Task.detached {\n var value: Double = 0\n var denominator: Double = 1\n var sign: Double = 1\n var increment: Double = 0\n\n repeat {\n increment = 4 / denominator\n value += sign * 4 / denominator\n denominator += 2\n sign *= -1\n } while increment > 0.000000001\n\n return value\n }.value\n}\n\nfunc updateThatCalculationIsUnderway() {\n statusLabel.text = "Calculating \xcf\x80"\n}\n\n@MainActor\nfunc updateWithResults(_ value: Double) {\n statusLabel.text = "Done"\n resultLabel.text = formatter.string(for: value)\n}\nRun Code Online (Sandbox Code Playgroud)\n注意:为了确保这种缓慢的同步计算calculatePi不在当前参与者(大概是主要参与者)上运行,我们需要一个\xe2\x80\x9c非结构化任务\xe2\x80\x9d。具体来说,我们需要一个\xe2\x80\x9c分离任务\xe2\x80\x9d,即不在当前actor上运行的任务。正如《Swift 编程语言:并发:任务和任务组》的非结构化并发部分所述:
\n\n要创建在当前参与者上运行的非结构化任务,请调用
\nTask.init(priority:operation:)初始化程序。要创建不属于当前参与者的非结构化任务(更具体地称为分离任务),请调用类Task.detached(priority:operation:)方法。
| 归档时间: |
|
| 查看次数: |
10077 次 |
| 最近记录: |