后台队列性能迅速?

时间:2018-11-04 14:24:50

标签: ios swift grand-central-dispatch

关注我的问题here

我有一个lotsOfWork()方法,可能需要一些时间才能完成。它运行时,用户需要等待它完成。我想向用户提供反馈,以便他了解发生了什么。

我现在有以下代码来运行我的lotsOfWork()方法,同时允许它更新显示其进度的标签:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        DispatchQueue.global(qos: .background).async {
            self.lotsOfWork()
        }
    }

    func lotsOfWork() {
        for i in 1...10 {
            DispatchQueue.main.async {
                self.label.text = "Working on item \(i)..."
            }
            sleep(1) // Simulating lots of work
        }
    }
}

但这也意味着lotsOfWork()方法将在后台队列中执行,而不是在main中执行。

当lotsOfWork()正在运行时,主队列中什么都没有发生,除了更新标签。用户只能等待。

问题1:这是一个重大的性能问题吗?工作需要更多时间才能完成吗?

问题2:如果这是一个问题,有没有办法让lotsOfWork()方法在main中运行,同时仍然可以更新label.text >?

我尝试使用DispatchQueue.main.async甚至2个嵌套的DispatchQueue.main.async,但这不会更新label.text。

我也尝试过使用setNeedsDisplay()和setNeedsLayout(),但这不会改变任何内容。

在main中执行lotsOfWork()不会有问题,因为用户需要等待此工作完成才能继续。但是,如果在main中运行lotsOfWork(),我无法实时更新label.text。

2 个答案:

答案 0 :(得分:4)

您请求的QoS(服务质量)不正确。您已请求background

  

用于非用户启动或不可见的工作。通常,用户不会意识到这项工作正在进行中。例如,预取内容,搜索索引,备份或与外部系统同步数据。

背景任务是优先级最低的任务,原则上永远不会执行(至少,您应该愿意接受数小时或更长时间的延迟)。

如果用户请求该操作并且必须等待该操作完成,则正确的QoS为.userInitiated

  

用于执行用户明确要求的工作,并且必须立即显示其结果以便允许进一步的用户交互。例如,在用户在邮件列表中选择它之后加载电子邮件。

此QoS级别可以(并且通常)与主队列一样性能,尽管通常应该避免对系统将要做什么进行第二次猜测,只是确保使用符合意图的QoS标记操作。最好的介绍是Concurrent Programming with GCD in Swift 3

我通常发现,当人们选择.background(最低QoS)时,他们通常表示.utility,而当他们选择.userInteractive(最高级别)时,他们通常表示{{ 1}}。最高和最低级别具有非常特殊的用例,这些用例很少出现。如果您在不到一天的时间内需要结果,则不是.userInitiated,如果要花费16毫秒以上的时间来完成,则不是.background

答案 1 :(得分:1)

  1. 根据发现的Apple文档here
  

由于高优先级的工作比低优先级的工作执行得更快,资源更多,因此与低优先级的工作相比,通常需要更多的精力。为您的应用执行的工作准确地指定适当的QoS类可确保您的应用具有响应能力和能源效率。

答案是。优先级较低的队列可能获得的资源较少,因此执行速度可能较慢。

  1. 答案是。在不阻止UI更新的情况下,您无法在main上执行相对繁重的工作。

如果您有兴趣在Swift中学习并发,建议您阅读Umberto Raimondi编写的this post。这是到目前为止我所见过的最好的Swift并发指南。