简体   繁体   English

swift中后台队列的性能?

[英]Performance of background queue in swift?

Following up on my question here . 这里跟进我的问题。

I have a method lotsOfWork() that may take some time to complete. 我有一个方法lotsOfWork()可能需要一些时间才能完成。 While it runs, the user needs to wait for it to complete. 在运行时,用户需要等待它完成。 I'd like to provide feedback to the user, so that (s)he sees what is going on. 我想向用户提供反馈,以便他看到发生了什么。

I now have the following code to run my lotsOfWork() method, while allowing it to update a label showing its progress: 我现在有以下代码来运行我的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
        }
    }
}

But this also means the lotsOfWork() method will be executed in the background queue and not in main. 但这也意味着lotsOfWork()方法将在后台队列中执行,而不是在main中执行。

While lotsOfWork() is running, nothing really happens in the main queue - except from updating the label. 当lotsOfWork()运行时,主队列中没有任何事情发生 - 除了更新标签。 The user cannot do anything but wait. 除了等待,用户不能做任何事情。

Question 1: Is this a substantial performance issue? 问题1:这是一个重大的性能问题吗? Will the work need more time to complete? 这项工作需要更多时间才能完成吗?

Question 2: If this is an issue, is there a way to let the lotsOfWork() method run in main, while still being able to update the label.text ? 问题2:如果这是一个问题,有没有办法让lotOfWork()方法在main中运行, 同时仍然能够更新label.text

I tried to use DispatchQueue.main.async and even 2 nested DispatchQueue.main.async, but this does not update the label.text. 我尝试使用DispatchQueue.main.async甚至2个嵌套的DispatchQueue.main.async,但这不会更新label.text。

I also tried using setNeedsDisplay() and setNeedsLayout(), but this does not change anything. 我也尝试使用setNeedsDisplay()和setNeedsLayout(),但这并没有改变任何东西。

It would not be an issue to execute lotsOfWork() in main, because the user needs to wait for this work to complete before continuing. 在main中执行lotsOfWork()不是问题,因为用户需要等待这项工作完成才能继续。 But I can't get the label.text to be updated in real time if lotsOfWork() runs in main. 但是如果lotsOfWork()在main中运行,我无法实时更新label.text。

Your requested QoS (quality of service) is incorrect. 您请求的QoS(服务质量)不正确。 You've requested background : 你已经要求background

Used for work that is not user initiated or visible. 用于非用户启动或可见的工作。 In general, a user is unaware that this work is even happening. 通常,用户不会意识到这项工作甚至正在发生。 For example, pre-fetching content, search indexing, backups, or syncing of data with external systems. 例如,预读内容,搜索索引,备份或与外部系统同步数据。

Background tasks are the lowest priority tasks, and in principle might never be executed (at a minimum, you should be willing to accept delays of hours or more). 后台任务是优先级最低的任务,原则上可能永远不会执行(至少,您应该愿意接受数小时或更长时间的延迟)。

If the user requested the operation and must wait for it to complete, then then correct QoS is .userInitiated : 如果用户请求了操作并且必须等待它完成,那么正确的QoS是.userInitiated

Used for performing work that has been explicitly requested by the user, and for which results must be immediately presented in order to allow for further user interaction. 用于执行用户明确请求的工作,并且必须立即显示结果以允许进一步的用户交互。 For example, loading an email after a user has selected it in a message list. 例如,在用户在消息列表中选择电子邮件后加载电子邮件。

This QoS level can be (and often is) as performant as the main queue, though you should in general avoid seconding-guessing the system about what it will do and just make sure you tag operations with the QoS that matches the intent. 这个QoS级别可以(并且经常)与主队列一样高效,但您通常应该避免借调猜测系统将执行的操作,并确保使用与意图匹配的QoS标记操作。 The best introduction to all of this is Concurrent Programming with GCD in Swift 3 . 所有这些的最佳介绍是在Swift 3中使用GCD进行并发编程

I generally find that when people choose .background (the lowest QoS), they usually meant .utility , and when they choose .userInteractive (the highest level), they usually meant .userInitiated . 我通常发现当人们选择.background (最低的QoS)时,他们通常意味着.utility ,当他们选择.userInteractive (最高级别)时,他们通常意味着.userInitiated The highest and lowest levels have very special use cases that don't come up very often. 最高级别和最低级别具有非常特殊的用例,这些用例不常出现。 If you need the result in less than a day, you don't mean .background , and if it takes more than 16ms to complete, you don't mean .userInteractive . 如果您在不到一天的时间内需要结果,那么您并不是指.background ,如果完成时间超过.background ,则.userInteractive

  1. According to Apple documentation found here : 根据Apple文档在此处找到:

Because higher priority work is performed more quickly and with more resources than lower priority work, it typically requires more energy than lower priority work. 由于优先级较高的工作比低优先级工作执行得更快,资源更多,因此通常需要比低优先级工作更多的能量。 Accurately specifying appropriate QoS classes for the work your app performs ensures that your app is responsive and energy efficient. 为您的应用程序执行的工作准确指定适当的QoS类可确保您的应用程序具有响应性和节能性。

The answer is yes . 答案是肯定的 Lower priority queue may get less resources, therefore may have slower execution. 较低优先级队列可能获得较少的资源,因此执行速度较慢。

  1. The answer is no . 答案是否定的 You cannot perform relatively heavy work on main without blocking UI updates. 在不阻止UI更新的情况下,您无法在main上执行相对繁重的工作。

If you're interested in learning Concurrency in Swift, I suggest you to read this post creates by Umberto Raimondi. 如果你对学习Swift中的Concurrency感兴趣,我建议你阅读Umberto Raimondi创建的这篇文章 This is the best Swift concurrency guide I've seen so far. 这是迄今为止我见过的最好的Swift并发指南。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM