两件事情:
1)您提供的代码安排在哪个队列上?因为它听起来像那个队列可能会与你的下载任务共享它的 qos。调度到另一个队列确实需要多个步骤。因此,仅仅因为传递了“comment1”,其他队列之一可能会在您调度时获得线程时间来做一些工作。这会导致一些延迟,是的,这似乎是最可能的原因。
2) WWDC 2016 视频Concurrent Programming with GCD in Swift 3可能会有所帮助。如果 cpu 的所有核心都已忙于其他任务,则将新内容分派到更高优先级的队列不会立即自动启动任务。GCD 会尽力而为,但也许您在那些其他队列上的任务非常紧张/正在做中断会导致问题的事情。
因此,如果您有必须立即启动的内容,请确保一个 CPU 内核/线程处于空闲状态。我会尝试使用OperationQueue
并设置它的maxConcurrentOperationCount
. 然后将所有下载操作放到该操作队列中,让核心/线程准备好启动音频。
但是我认为选项 2 在这里无效,因为您说它有时需要几秒钟。
更新:
正如您所说,您提供的代码在一个也用于您的下载任务的队列上运行,这主要是一个错误的架构设计,我很遗憾地说,如果没有看到您的全部内容,任何人都无法提出解决方案项目以帮助更好地构建它。您必须弄清楚何时以及将哪些任务分配到什么优先级。
以下是我对您提供的代码的想法:
你为什么使用.barrier
国旗?此标志确保队列不会执行其他并发任务,如果您的数据被多个任务操作并希望避免“竞争条件”,那就太好了。但是,这也意味着在您分派块之后,它将等待在它之前分派的其他任务,然后阻塞队列来执行您的任务。
正如其他人所评论的那样,使用仪器分析您的代码可能会显示这种行为。
以下是我将如何构建您的音频请求:
//A serial (not concurrent) audio queue. Will download one data at a time and play audio
let audioQueue = DispatchQueue(label: "Audio Queue My App", qos: .userInitiated)
//I'm on the main queue here!
audioQueue.async {
//I'm on the audio queue here, thus not blocking the main thread
let result = downloadSomeData()
//Download is done here, and I'm not being blocked by other dispatch queues if their priority is lower.
switch result {
case .success(let data):
//Do something with the data and play audio
case .failure(let error):
//Handle Error
}
}
///Downloads some audio data
func downloadSomeData() -> Swift.Result<Data, Error> {
//Create dispatch group
let dg = DispatchGroup()
dg.enter()
///my audio data
var data: Data?
//Dispatch onto a background queue OR place a block operation onto your OperationQueue
DispatchQueue.global(qos: .background).async {
//Download audio data... Alamofire/ URLSession
data = Data()
dg.leave()
}
dg.wait()
//Data was downloaded! We're back on the queue that called us.
if let nonOptionalData = data {
return .success(nonOptionalData)
} else {
return .failure(NSError(domain: "MyDomain", code: 007, userInfo: [ NSLocalizedDescriptionKey: "No data downloaded, failed?"]))
}
}
关于选项#2:
可以使用 检索活动核心的数量ProcessInfo().activeProcessorCount
。请注意,理论上这个值可能会在运行您的应用程序时由于热节流或其他原因而改变。通过使用此信息并将 a 设置maxConcurrentOperationCount
为OperationQueue
等于活动处理器的数量,您可以确保操作/任务不必共享 cpu 时间。(只要没有其他 DispatchQueue 正在运行。)但是这种方法并不安全。只需要一名团队成员在未来将任务分派到其他地方即可。
但是,此信息的有用之处在于,您可以限制下载任务使用的资源量,方法是拥有一个专用的 OperationQueue,例如最多 2 个并发操作,并将所有后台工作放在此 DispatchQueue 上。您的 CPU 很可能不会充分发挥其潜力并留下一些空间。