【问题标题】:iOS RunLoop and DispatchQueue.main.asynciOS RunLoop 和 DispatchQueue.main.async
【发布时间】:2020-10-17 17:13:09
【问题描述】:

为什么print("2") 部分从未在以下代码中被调用? 我认为内部 main.async 会将块推送到主循环的队列中, 然后RunLoop.run 会执行它,但显然不是这样。 (它会打印1runrunrun 等)

另外,如果我删除外部main.async,然后直接运行该块中的代码 (仍在主队列中,在一个新的单视图应用程序的viewDidLoad 中), 然后内部的main.async 块确实被执行(打印1run2)。 为什么这种变化会产生如此大的影响?

var x = -1
DispatchQueue.main.async {   //  comment out this line for question #2
    print("1")
    x = 1
    DispatchQueue.main.async {
        print("2")
        x = 2
    }
    while x == 1 {
        print("run")
        RunLoop.main.run(mode: .default, before: Date() + 1)
    }
}   //  comment out this line for question #2

【问题讨论】:

  • FWIW,在运行循环上旋转的笨拙技术有点不合时宜。我们现在不经常看到它。当有人试图使一个固有的异步进程同步运行时,通常使用它,并使用这种运行循环技术至少让运行循环来处理事件。但正如您所发现的,它并不理想,并且会引入这些问题。此外,通常还有更好、更有效的解决方案(例如,采用异步模式而不是与之抗衡)。
  • @Rob 我知道,我知道。我试图做类似事情的用例基本上是一个调试工具,它用联网的 RPC 调用代替了通常的同步调用,理想情况下,如果我可以使用它而不必修改调用者,那就太好了。
  • 好的。但我不得不说,至少为了未来的读者。太多不熟悉异步模式的新开发人员倾向于使用这些变通方法。无意冒犯。

标签: ios nsrunloop dispatch-queue


【解决方案1】:

在您的第一个示例中,第一个 async 阻塞了 main 串行队列,直到它从外部 async 调用返回,这在 x1 时不会发生。内部 GCD async 任务(将 x 更新为 2)将永远没有机会运行,因为串行 GCD 队列现在在 while 循环中被阻塞。在主运行循环上尝试run 不会规避 GCD 串行队列的规则/行为。它只会耗尽已添加到其中的事件的运行循环。

在你的第二个例子中,你没有阻塞 GCD main 队列,所以当你点击 run 时,将 x 更新为 2 的调度块确实有机会运行,让它继续.

最重要的是,不要将 GCD 主队列和主运行循环混为一谈。是的,它们都使用主线程,但不能使用运行循环来规避串行 GCD 队列的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 2018-12-01
    • 1970-01-01
    相关资源
    最近更新 更多