【问题标题】:Is it ok to use DispatchQueue inside Task?可以在 Task 中使用 DispatchQueue 吗?
【发布时间】:2022-08-24 12:03:17
【问题描述】:

我现在正在使用 async-await 和 Task 将我的一些代码转换为并发代码。我想知道的一件事是可以在 Task 实例中使用 DispatchQueue ,例如

Task {
    await someHeavyStuff()
    DispatchQueue.main.async {
        someUIThreadStuff()
    }
}

据我所知,Task 和 DispatchQueue 处理异步事物的机制几乎没有什么不同,所以我担心同时使用这两种方法会搞乱线程系统。

(我知道在这种情况下我可以使用MainActor.run {}

  • 您几乎肯定不想在代码中混合和匹配并发模型。你有理由吗不能使用MainActor.run,还是出于好奇?
  • @ItaiFerber 这只是我的好奇心

标签: swift


【解决方案1】:

你可以使用DispatchQueue.main.async { … },但你真的应该放弃这个模式。但是,如果您有一个大型复杂项目,您正在慢慢过渡到 Swift 并发,并且还没有时间清理它,是的,您现在可以摆脱这个 GCD 调用。

但正确的解决方案是将someUIThreadStuff 标记为@MainActor 并停用DispatchQueue.main.async { … }。这是一个微不足道的修复,MainActor.run { … } 也是如此。在过渡到 Swift 并发的过程中你可能要处理的所有事情中,这是最容易做到的事情之一,并且可以摆脱 GCD API。

当你过渡到 Swift 并发时,你必须特别小心的地方是你使用锁和信号量的地方,或者你阻塞当前线程的地方。 Swift 并发无法推理这些,而这些可能是问题的根源。但是对主队列的延迟调度不太可能导致问题,尽管您当然应该尽早将其删除。请参阅Swift concurrency: Behind the scenes,特别是关于运行时合约的讨论,以永远不会阻止向前进展。


当我查看您的代码 sn-p 时,我会更关心 Task { … } 以启动 someHeavyStuff。 “startHeavyStuff”这个名字暗示了一些计算量很大的东西,阻塞了当前线程。但Task { … } 用于启动异步任务对现在的演员,不适用于在后台线程上运行“繁重”任务。现在,someHeavyStuff 以某种方式从当前的演员身上得到了它,然后忽略这个警告。但请注意不要假设Task { … } 的行为会像DispatchQueue.global().async { … },因为它不会。


我建议观看 WWDC 2021 Swift concurrency: Update a sample app。它介绍了重构遗留代码的非常实用的练习。

【讨论】:

    猜你喜欢
    • 2018-05-01
    • 1970-01-01
    • 2021-06-07
    • 2021-03-24
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    相关资源
    最近更新 更多