新的 Async/Await 语法看起来很棒!但我想知道如何实现我自己的异步实现。
我偶然发现了这个 API:
- https://developer.apple.com/documentation/swift/task/3862702-suspend (
产量
概述) - https://developer.apple.com/documentation/swift/task/3814840-yield (重命名为
暂停
)
此 API 允许我随时手动暂停任务。问题是,我不确定应该如何做,才能从并发中受益而不是避免不良做法。
也就是说,我不知道Task.suspend()的最佳实践
例如:
func example() async {
for i in 0..<100 {
print("example", i)
await Task.suspend() // <-- is this OK?
}
}
一些具体问题:
- 应该多久调用一次
挂起
? - 应该在密集操作之前还是之后调用
挂起
? (例如:IO、加密等...) - 对
挂起
的调用是否应该有最大数量? - 密集调用
suspend
的“代价”是多少? - 什么时候不应该调用
挂起
? - 还有其他方法可以实现这种并发(异步/等待风格,而不是 GCD)
现实生活中的例子,我正在实现一个加密大文件内容的函数,因为它是一个IO+加密密集型任务,所以它应该是异步的,我想知道如何使用Task.suspend
(或任何其他异步/等待工具)以使其异步。
最佳答案
调用 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
在其自己的协作并发队列上工作,如果您不想暂停,请考虑将任务移至非默认优先级(队列),例如任务(优先级:.background)
或在单独的队列上运行繁重的任务。
关于Swift 5.5,何时在自定义异步实现中使用 `Task.suspend`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68646769/