ios - swift中后台队列的性能?
问题描述
在这里跟进我的问题。
我有一个方法lotsOfWork() 可能需要一些时间才能完成。当它运行时,用户需要等待它完成。我想向用户提供反馈,以便他(她)看到正在发生的事情。
我现在有以下代码来运行我的 lotOfWork() 方法,同时允许它更新显示其进度的标签:
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:如果这是一个问题,有没有办法让 lotOfWork() 方法在 main 中运行,同时仍然能够更新 label.text?
我尝试使用 DispatchQueue.main.async 甚至 2 个嵌套的 DispatchQueue.main.async,但这不会更新 label.text。
我也尝试使用 setNeedsDisplay() 和 setNeedsLayout(),但这并没有改变任何东西。
在 main 中执行lotsOfWork() 不会有问题,因为用户需要等待这项工作完成才能继续。但是如果lotsOfWork() 在main 中运行,我无法实时更新label.text。
解决方案
您请求的 QoS(服务质量)不正确。您已要求background
:
用于非用户发起或不可见的工作。通常,用户甚至不知道这项工作正在发生。例如,预取内容、搜索索引、备份或与外部系统同步数据。
后台任务是最低优先级的任务,原则上可能永远不会执行(至少,您应该愿意接受数小时或更长时间的延迟)。
如果用户请求操作并且必须等待它完成,那么正确的 QoS 是.userInitiated
:
用于执行用户明确请求的工作,并且必须立即呈现结果以允许进一步的用户交互。例如,在用户在消息列表中选择电子邮件后加载它。
此 QoS 级别可以(并且通常)与主队列一样高效,尽管您通常应该避免间接猜测系统将做什么,并确保使用与意图匹配的 QoS 标记操作。对所有这一切的最佳介绍是Swift 3 中使用 GCD 进行并发编程。
我一般发现当人们选择.background
(最低 QoS)时,他们通常是指.utility
,而当他们选择.userInteractive
(最高级别)时,他们通常是指.userInitiated
。最高层和最低层都有非常特殊的用例,这些用例并不经常出现。如果你需要不到一天的结果,你不是说.background
,如果需要超过 16ms 才能完成,你不是说.userInteractive
。
推荐阅读
- python - 在可访问的页面上出现 404 错误
- android-studio - 有没有办法在 IntelliJ/Android Studio 中对 dart 的文本颜色进行更细粒度的控制?
- youtube-api - 尽管视频中存在观看次数,但按国家/地区划分的 Youtube 观看次数返回空列表
- django - 如何从 api 获取变量并在 Nginx 配置文件中定义
- javascript - 如何将 CSS 样式应用于 Angular 中动态创建的 DOM 对象
- asp.net - 如何结合调试 azureapp 服务和 IIS 托管的 WCF?
- reactjs - 无法在 React Native 的自定义抽屉内容功能组件中使用 useContext 挂钩
- java - 在 Reactor 中做异步副作用的最佳方法是什么?
- windows - Fluentbit 创建 TCP 连接
- r - ggfortify 无法加载 - U_FILE_ACCESS_ERROR