Swift 5.5的async let - 错误:表达式是“async”,但没有标记为“await”。

17

WWDC21推出了Swift 5.5,其中包括async/await。在探索Swift中的结构化并发认识Swift中的async/await WWDC21会话之后,我正在尝试使用async let函数。

这是我的Playground代码:

func doIt() async -> String {
    let t = TimeInterval.random(in: 0.25 ... 2.0)
    Thread.sleep(forTimeInterval: t)
    return String("\(Double.random(in: 0...1000))")
}

async {
    async let a = doIt()
    async let b = doIt()
    async let c = doIt()
    async let d = doIt()
    
    let results = await [a, b, c, d]
    for result in results {
        print("  \(result)")
    }
}

然而,对于每一个 "async let" 行,我都会收到这个错误:

error: AsyncLetSwift55WWDC21.playground:12:15: error: expression is 'async' but is not marked with 'await'
    async let a = doIt()
              ^
              await 

Paul Hudson的博客展示了这个例子: Hacking With Swift async let example

在Exploring structured currency视频中,大约在8:10处有这个例子: enter image description here

编辑:这似乎是一个Playground特有的问题。根据Apple Developer Forums上相同问题的建议,在macOS命令行项目中运行相同的代码(好的,我在异步块后添加了sleep(10)到源文件末尾,以便应用程序在异步调用完成之前不会终止)不会出错并且产生正确的输出。

这是一个bug,还是我没有理解什么?

3个回答

8

我的建议是:不要在游乐场尝试这个。目前游乐场还没有准备好这些东西。但你的代码可以在真实项目中编译并运行。以下是一个示例:

class ViewController: UIViewController {
    
    func doIt() async -> String {
        let t = TimeInterval.random(in: 0.25 ... 2.0)
        Thread.sleep(forTimeInterval: t)
        return String("\(Double.random(in: 0...1000))")
    }
    func test() {
        async {
            async let a = doIt()
            async let b = doIt()
            async let c = doIt()
            async let d = doIt()
            
            let results = await [a, b, c, d]
            for result in results {
                print("  \(result)")
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        test()
    }
}

谢谢,马特。我今天开始测试,但在 Playground 中遇到了许多奇怪的错误。有一个问题。你使用 Thread.sleep(),但规范推荐使用新的 Task.sleep()。问题是 Task.sleep() 目前无法正常工作。你能让它工作吗?https://docs.swift.org/swift-book/LanguageGuide/Concurrency.html - Mikiko Jane
2
据我所知,Task.sleep 目前只适用于非常小的值。不确定出了什么问题。 - matt
1
由于Task.sleep目前无法工作,所以您可以使用withCheckedContinuation作为解决方法,在其中您可以调用DispatchQueue.main.asyncAfter - user1046037
@user1046037 当然可以!请参考我的 https://www.biteinteractive.com/swift-5-5-asynchronous-looping-with-async-await/ 以获取示例。 - matt

4

作为macOS命令行项目进行构建(Xcode: 文件 -> 新建 -> 项目, 然后从macOS选项卡中选择 "命令行工具"),代码可以完美运行。 (这是来自Apple Developer Forums的回复建议。)

我在末尾添加了一个单独的sleep(10),以便命令行工具不会在异步调用完成之前退出:

import Foundation

print("Hello, world!")

func doIt() async -> String {
    let t = TimeInterval.random(in: 0.25 ... 2.0)
    Thread.sleep(forTimeInterval: t)
    return String("\(Double.random(in: 0...1000))")
}

async {
    async let a = doIt()
    async let b = doIt()
    async let c = doIt()
    async let d = doIt()
    
    let results = await [a, b, c, d]
    for result in results {
        print("  \(result)")
    }
}
sleep(10)

这会产生预期的控制台输出(注意:实际值每次运行时可能会有所不同)*。
Hello, World!
  415.407747869283
  574.28639828183
  689.4706625185836
  385.56539085197113
Program ended with exit code: 0

1
这与我所说的有何不同? - matt

-4

它作为 macOS 命令行项目运行良好,但当我将其创建为 iOS 项目时,

这些代码:

async let a = doIt()
async let b = doIt()
async let c = doIt()
async let d = doIt()

不要并行运行。


请注意,如果您在真实硬件上运行,async/await的任务池可能非常小,并且完全是协作式的。这意味着,如果您创建了一个异步任务,它执行CPU工作而不等待或让出,它将独占池中极少数可用线程之一。这意味着只有很少的任务实际上会运行。 - Dag Ågren

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