swift - DispatchQueue 是否在其自己的线程中运行?

标签 swift grand-central-dispatch dispatch-queue

我试图了解 DispatchQueues 的真正工作原理,我想知道假设 DispatchQueues 有自己的管理线程是否安全?例如,让我们以串行队列为例。在我的理解中——因为它是串行的,新任务只能在当前任务结束后才能开始,所以“某人”必须从队列中取出新任务并提交执行!所以,基本上看来队列必须留在它自己的线程中,该线程将分派(dispatch)存储在队列中的任务。这是正确的还是我误解了什么?

最佳答案

不,您不应该假设 DispatchQueues 有自己的托管线程,并且它不必在同一线程上执行所有任务。它只保证在前一个任务完成后接下一个任务:

Work submitted to dispatch queues executes on a pool of threads managed by the system. Except for the dispatch queue representing your app's main thread, the system makes no guarantees about which thread it uses to execute a task.

( source )

实际上,非常有可能,同一个线程将运行同一个顺序队列中的多个或所有顺序任务——前提是它们彼此靠近(及时)运行。我推测这不是纯粹的巧合,而是优化(避免上下文切换)。但这不是保证

事实上你可以做这个小实验:

let serialQueue = DispatchQueue(label: "my.serialqueue")
var incr: Int = 0

DispatchQueue.concurrentPerform(iterations: 5) { iteration in

    // Rundomize time of access to serial queue
    sleep(UInt32.random(in: 1...30))
    
    // Schedule execution on serial queue
    serialQueue.async {
        incr += 1
        print("\(iteration) \(Date().timeIntervalSince1970) incremented \(incr) on \(Thread.current)")
    }
}

你会看到这样的东西:

3 1612651601.6909518 incremented 1 on <NSThread: 0x600000fa0d40>{number = 7, name = (null)}
4 1612651611.689259 incremented 2 on <NSThread: 0x600000faf280>{number = 9, name = (null)}
0 1612651612.68934 incremented 3 on <NSThread: 0x600000fb4bc0>{number = 3, name = (null)}
2 1612651617.690246 incremented 4 on <NSThread: 0x600000fb4bc0>{number = 3, name = (null)}
1 1612651622.690335 incremented 5 on <NSThread: 0x600000faf280>{number = 9, name = (null)}

迭代并发开始,但我们让它们随机休眠,以便它们在不同时间访问串行队列。结果是同一个线程不太可能执行每个任务,尽管任务执行是完全顺序的。

现在,如果您删除顶部的 sleep,导致所有迭代同时请求访问顺序队列,您很可能会看到所有任务都将在同一个线程上运行,我认为是优化,不是巧合:

4 1612651665.3658218 incremented 1 on <NSThread: 0x600003c94880>{number = 6, name = (null)}
3 1612651665.366118 incremented 2 on <NSThread: 0x600003c94880>{number = 6, name = (null)}
2 1612651665.366222 incremented 3 on <NSThread: 0x600003c94880>{number = 6, name = (null)}
0 1612651665.384039 incremented 4 on <NSThread: 0x600003c94880>{number = 6, name = (null)}
1 1612651665.3841062 incremented 5 on <NSThread: 0x600003c94880>{number = 6, name = (null)}

这是关于 iOS Concurrency "Underlying Truth" 主题的精彩读物

关于swift - DispatchQueue 是否在其自己的线程中运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66081842/

相关文章:

ios - 在生产环境中使用 Realm Collection Change 通知

ios - Swift UIAlertController,文本中带有 url

ios - 使用 Swift 以编程方式在 Mapkit 中倾斜 map

c、正确使用线程

swift - 完成处理程序的返回值未在 DispatchQueue.main.async block 中更新

IOS 发布问题(无效的 Swift 支持)

ios - dispatch_get_current_queue() 已弃用,是否有安全 CoreData 的替代方案?

ios - 使用动画更新 UITableView 时的多线程问题

swift - 如何在 swift 中停止 dispatchQueue

ios - 在使用 Swift 的 iOS 应用程序中使用 DispatchQueue 等待数据从 Cloud Firestore 返回时遇到问题