【问题标题】:How to guarantee any DispatchQueue (or OperationQueue) to run only in non-main thread for asynchronous tasks?如何保证任何 DispatchQueue(或 OperationQueue)仅在异步任务的非主线程中运行?
【发布时间】:2019-06-20 00:06:29
【问题描述】:

到目前为止,我找不到有关此功能的任何提及。 AFAIK,根据定义,任何 GCD 队列都可以在主线程中运行。如果一个任务繁重的 GCDQ 选择了主线程来执行,它会对 UI 产生一些不好的影响。 (我说的是DispatchQueue.async案例)

如果当前线程被检测为主线程,则此情况的典型解决方法是跳过任务。但这会浪费系统资源并引入不必要的复杂性。我相信必须有一种声明方式来做到这一点。

有没有更好的方法?我有各种不应该在主线程上运行的任务。我尝试生成一个单独的线程,但效果不佳,因为 macOS 缺少未命名的信号量。尽管DispatchSemaphore 是使用未命名的信号量实现的,但我不确定将DispatchSemaphore 与pthread 一起使用是否安全,因为它是GCD 级别的对象。

【问题讨论】:

    标签: swift macos cocoa grand-central-dispatch qos


    【解决方案1】:

    到目前为止,最好的方法是将服务质量级别设置为后台。

    根据this document;

    ...系统在优先级设置为后台状态的线程上运行项目。 ...

    这个document 表示“主线程”的默认 QoS 设置为 GUI 应用程序的“用户交互”。

    ... 在应用程序中,主线程以用户交互的 QoS 级别运行。 ...

    以后是否可以更改 QoS 级别尚不清楚。无论如何,在默认设置下,系统不会将 QoS 级别较低的 GCD 任务发送到主线程。如果没有这样的线程可用,系统会产生一个新的。

    这是我的想法,我仍然无法从官方文档中找到明确提及。

    【讨论】:

    • 请注意,.background QoS 可能会被阻止数小时或数天,具体取决于系统电源情况。你不应该把东西放在.background 上,除非你的意思是“如果这个任务从来没有真正运行过也没关系”。通常你的意思是.utility(甚至更多时候,你的意思是.default)。通常,您不应该考虑 GCD 中的线程,并且绝对不要尝试绕过队列系统来针对特定线程。将您的块放在适当的队列中(使用DispatchQueue.global()),系统通常会做正确的事情。
    • 如果您想更深入地了解,请观看有关该主题的 WWDC 视频:developer.apple.com/videos/play/wwdc2017/706developer.apple.com/videos/play/wwdc2016/720
    • @RobNapier 感谢您的来信。我也会尝试.utility QoS 级别。我知道线程和 GCD 处于不同的级别。问题在于可能运行更长时间的非 UI 任务。不管好坏,Apple 平台上的 GCD 都是在 pthread 之上实现的。因此,它们无法摆脱 pthread 规则。以 GCD 的当前定义,全局队列或任何私有串行队列都可以将任务发送到主线程,如果其中任何一个时间超过 100 毫秒,则会严重降低用户体验质量。因此,我需要一种方法来保证永远不会将特定任务发送到主线程。
    • 如果 Apple 明确声明永远不会在主线程中执行全局/串行队列,我不会担心,不幸的是,到目前为止,我找不到这样的提及。我会看看视频。我希望我能在这里找到一些提及。
    • @RobNapier 我找不到任何关于禁止在主线程中运行非主队列任务的信息。到目前为止,QoS 似乎是唯一的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2016-10-05
    • 1970-01-01
    • 2021-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多