1

新的 Async/Await 语法看起来很棒!但我想知道如何实现我自己的异步实现。

我偶然发现了这个 API:

这个 API 允许我在选择时手动挂起任务。问题是,我不确定我应该怎么做,以便从并发中受益而不是避免不良做法。

换句话说,我不知道的最佳实践Task.suspend()

例如:

func example() async {
    for i in 0..<100 {
        print("example", i)
        await Task.suspend() // <-- is this OK?
    }
}

一些具体问题:

  • 应该多久打电话一次suspend
  • 应该suspend在密集手术之前还是之后调用?(例如:IO、Crypto 等...)
  • 应该有最大数量的调用suspend吗?
  • suspend密集呼叫的“价格”是多少?
  • 什么时候不应该打电话suspend
  • 有没有其他方法来实现这种并发(异步/等待风格,而不是 GCD)

现实生活中的例子,我正在实现一个加密大文件内容的函数,因为它是一个 IO+Crypto 密集型任务,它应该是异步的,我想知道如何使用Task.suspend(或任何其他异步/等待工具)来实现它异步。

4

1 回答 1

2

调用Task.suspend()将暂停当前任务几毫秒,以便为可能正在等待的任何任务留出一些时间,如果您在循环中进行密集工作并且所有任务都使用相同的优先级,这一点尤其重要。否则,您的繁重任务可能会停止应用程序中的所有异步代码。例如:

func f() async {
    for _ in 0...10 {
        var arr = (1...10000).map {_ in arc4random()}
        arr.sort()
    }
    print("f")
}

func z() async {
    print("z")
}

// Run in parallel

Task {
    await f()
}

Task {
    await z()
}

输出:

f
z

如您所见z(),等待是f()因为它多次对大型数组进行排序的长时间运行操作。要解决此问题,您可以Task.suspend()在循环中添加:

func f() async {
    for _ in 0...10 {
        var arr = (1...10000).map {_ in arc4random()}
        arr.sort()

        await Task.suspend() // Voluntarily suspend itself 
    }
    print("f")
}

输出:

z
f

async/await在其自己的协作并发队列上工作,如果您不想暂停,请考虑将您的任务移动到非默认优先级(队列),例如Task(priority: .background)或在单独的队列上运行繁重的任务。

于 2021-08-09T22:18:01.867 回答