Swift 中的await 如何处理元组?

glo*_*loo 2 parallel-processing concurrency async-await swift

我试图确保我理解 的行为await。假设我们有以下函数:

func do() async {
  //code
}
func stuff() async {
  //code
}
Run Code Online (Sandbox Code Playgroud)

以下语句将按do顺序运行stuff

await do()
await stuff()
Run Code Online (Sandbox Code Playgroud)

但下面的语句会并行do运行吗?stuff

await (do(), stuff())
Run Code Online (Sandbox Code Playgroud)

我不确定如何在 Xcode 中检查我的代码是并行运行还是顺序运行。

Rob*_*Rob 5

简短回答:

\n

如果你想并发执行,可以使用async let模式或任务组。

\n
\n

长答案:

\n

你说:

\n
\n

但是下面的语句将并行运行 do 和 stuff ,正确吗?

\n
await (do(), stuff()) \n
Run Code Online (Sandbox Code Playgroud)\n
\n

不,他们不会。

\n

这可以通过以下经验得到最好的说明:

\n
    \n
  • 让任务花费足够的时间,以便并发行为很容易体现出来;和
  • \n
  • 使用 Instruments 中的 \xe2\x80\x9cPoints of Interest\xe2\x80\x9d 工具(例如,通过选择 \xe2\x80\x9cTime Profiler\xe2\x80\x9d 模板)以图形方式表示时间间隔。
  • \n
\n

使用元组方法考虑以下代码:

\n
import os.log\n\nprivate let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest)\n
Run Code Online (Sandbox Code Playgroud)\n

和:

\n
func example() async {\n    let values = await (self.doSomething(), self.doSomethingElse())\n    print(values)\n}\n\nfunc doSomething() async -> Int {\n    spin(#function)\n    return 1\n}\n\nfunc doSomethingElse() async -> Int {\n    spin(#function)\n    return 42\n}\n\nfunc spin(_ name: StaticString) {\n    let id = OSSignpostID(log: log)\n    os_signpost(.begin, log: log, name: name, signpostID: id, "begin")\n\n    let start = CACurrentMediaTime()\n    while CACurrentMediaTime() - start < 1 { }   // spin for one second\n\n    os_signpost(.end, log: log, name: name, signpostID: id, "end")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这会产生一个图表,显示它不是同时发生的:

\n

在此输入图像描述

\n

然而:

\n
func example() async {\n    async let foo = self.doSomething()\n    async let bar = self.doSomethingElse()\n    let values = await (foo, bar)\n    print(values)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这确实会导致并发执行:

\n

在此输入图像描述

\n
\n

现在,在上面的示例中,我更改了函数,以便它们返回值(因为这实际上是使用元组具有实际意义的唯一上下文)。

\n

但是,如果它们没有返回值并且您希望它们并行运行,则可以使用任务组:

\n
func experiment() async {\n    await withTaskGroup(of: Void.self) { group in\n        group.addTask { await self.doSomething() }\n        group.addTask { await self.doSomethingElse() }\n    }\n}\n\nfunc doSomething() async {\n    spin(#function)\n}\n\nfunc doSomethingElse() async {\n    spin(#function)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这会产生它们并行运行的相同图表。

\n

您也可以只创建Task实例,然后创建await它们:

\n
func experiment() async {\n    async let task1 = Task { await doSomething() }\n    async let task2 = Task { await doSomethingElse() }\n    _ = await task1\n    _ = await task2\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但是,当编译时可能未知所创建的任务数量时,任务组提供了更大的灵活性。

\n