在不支持并发的函数中使用“async”调用

29
我正在尝试在Swift 5.5中使用async/await。我有我的异步函数,但每当我尝试调用它时,就会出现以下错误:
“在不支持并发的函数中调用'async'”
以下是代码示例:
class TryThis {
    func getSomethingLater(_ number: Double) async -> String {
        // test - sleep for 3 seconds, then return
        Thread.sleep(forTimeInterval: 3)
        return String(format: ">>>%8.2f<<<", number)
    }
}

let tryThis = TryThis()

let result = await tryThis.getSomethingLater(3.141592653589793238462)
print("result: \(result)")

这个问题有什么解决方案吗?

5个回答

46
这里的答案是“await getSomethingLater”必须从异步上下文中调用。字面意思是将此更改为:
let result = await tryThis.getSomethingLater(3.141592653589793238462)
print("result: \(result)")

转换为:

Task {
    let result = await tryThis.getSomethingLater(3.141592653589793238462)
    print("result: \(result)")
}

所以整个事情就变成了:

class TryThis {
    func getSomethingLater(_ number: Double) async -> String {
        // test - sleep for 3 seconds, then return
        Thread.sleep(forTimeInterval: 3)
        return String(format: ">>>%8.2f<<<", number)
    }
}

let tryThis = TryThis()

Task {
    let result = await tryThis.getSomethingLater(3.141592653589793238462)
    print("result: \(result)")
}

这是输出结果:

结果: >>> 3.14<<<

在WWDC21的Meet async/await in Swift视频中有很棒的信息。


2
我收到了警告:'async(priority:operation:)'已被弃用:async已被Task.init替换,并将很快被删除。我认为这意味着这个答案不应再被接受。 - Ky -
@Ky 目前这个答案并没有使用'async(priority:operation:)'。正如你所提到的,它的替代方案是使用Task,而这个答案正在使用Task。这就是正确的答案。 - Mozahler
2
只是一个提示:您可以使用.pi而不是文字:tryThis.getSomethingLater(.pi) - Ky -

9

当从非async代码调用async代码(包括actor字段)时,必须将其包装在Task中:

Task {
    let result = await tryThis.getSomethingLater(3.141592653589793238462)
    print("result: \(result)")
}

如果你需要跳出异步上下文,可以使用传统的回调函数:

func awaitedResult(callback: @escaping (String) -> Void) {
    Task {
        let result = await tryThis.getSomethingLater(3.141592653589793238462)
        callback(result)
    }
}

awaitedResult { result in
    print("result: \(result)")
}

Swift by Sundell 还提供了一些涉及 Combine 的替代方案


进一步阅读:并发——Swift编程语言(Swift 5.5)


1
不错的答案,只是我发现你现在还需要在回调上加上 @escaping。 - kapace
1
糟糕!谢谢,@kapace;我在SO编辑器中编写,没有在编译器中检查它,这就是我的问题。 - Ky -

4

原始错误是由于Swift不支持“顶级”await(即在全局范围内的代码)所导致的。 这个错误仅意味着您需要为异步函数提供一个异步上下文,例如使用TaskTask.detachedTaskGroup,具体取决于您想要的行为。

Task.detached {
    let result = await tryThis.getSomethingLater(3.141592653589793238462)
    print("result: \(result)")
}

然而,当顶级等待(top-level await)被提议、实现和支持时,你的代码片段应该能够正常工作。 支持顶级等待是作为async/await原始提案的一部分被提及的SE-0296


2

在我的情况下,我只是重构了以下内容:

async { some-code-which-can-take-some-time }

使用:

Task { some-code-which-can-take-some-time }

0

当你试图从同步函数调用异步函数时,就会出现此错误。在Swift中不允许这样做,因为异步函数必须能够暂停自己和它们的调用者,而同步函数则不知道如何做到这一点。

func doAsyncWork() async {
    print("Doing async work")
}

func doRegularWork() {
    Task {
        await doAsyncWork()
    }
}

执行常规工作()

此处参考


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接