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

And*_*rty 3 grand-central-dispatch swift dispatch-queue

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

Kir*_* S. 5

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

提交到调度队列的工作在系统管理的线程池上执行。除了代表应用程序主线程的调度队列之外,系统不保证它使用哪个线程来执行任务。

来源

实际上,同一个线程很有可能运行来自同一个顺序队列的多个或所有顺序任务 - 前提是它们运行得彼此接近(在时间上)。我推测这不是纯粹的巧合,而是通过优化(避免上下文切换)。但这并不能保证

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

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)")
    }
}
Run Code Online (Sandbox Code Playgroud)

你会看到这样的东西:

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)}
Run Code Online (Sandbox Code Playgroud)

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

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

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)}
Run Code Online (Sandbox Code Playgroud)

这是关于iOS 并发“底层真相”主题的精彩读物