我正在将我的旧项目从DispatchQueue转换为async await,我在全局调度队列中 Package 了一个耗时的操作:
DispatchQueue.global().async {
self.processed = processData(input)
DispatchQueue.main.async {
render() // reload UI with self.processed
}
}
processData()
是耗时的同步操作render()
使用处理后的数据更新UI,并且需要在主线程上
看起来最接近全局队列的是使用Task.detached
,但是使用它我不能改变主参与者隔离的属性,例如。self.processed
。
然后我想到这样做:
processData(input: Input) async -> Output {
await withCheckedContinuation { continuation in
DispatchQueue.global().async {
let output = process(input)
continuation.resume(returning: output)
}
}
}
…
let processed = await processData(input)
render()
但感觉就像是为了使用async/await而使用DispatchQueue
。有什么想法吗谢谢!
2条答案
按热度按时间thtygnil1#
是的,理论上可以使用分离任务。
只需确保包含此代码的方法与主actor隔离,以及
render
方法,但processData
方法不是。例如,在一个本身是actor isolated的类型中,你只需要将processData
标记为nonisolated
:但我会明确建议不要使用
MainActor.run {…}
或Task { @MainActor in …}
模式。太脆了。找到合适的演员的负担不应该落在打电话的人的肩上。只要确保相关的方法和属性是参与者隔离的,编译器将确保您正确调用这些方法,跨越参与者隔离边界的值是Sendable
等。关于后一点的说明。当你在线程之间传递对象时,你必须让编译器知道它们是线程安全的,即
Sendable
。WWDC 2022视频Eliminate data races using Swift Concurrency在Swift 5.x中,如果你的类型是Sendable
,它不会总是警告你,所以考虑将“严格并发检查”构建设置更改为“完成”:第一次或第二次处理
Sendable
类型时,它可能看起来非常混乱,但希望上面的视频会有所帮助。但是一旦您掌握了Sendable
一致性,它将成为您的第二天性,并且您会想知道为什么您要经历过去所有那些线程安全问题。问题是分离的任务是非结构化的并发。也就是说,如果您取消父任务,它不会将取消传播到子任务。
所以,我可能会留在结构化并发中。例如,我可以将
processData
移动到它自己的actor中:hjqgdpho2#
您可以使用任务与后台优先级类似: