如果在串行 DispatchQueue 中触发上下文切换会发生什么情况?

What will happen if a context switch is triggered in a serial DispatchQueue?

原则上,一个连续的DispatchQueue会依次执行提交的任务。但是,如果在一个任务中触发了上下文切换(例如,调用 sleep)怎么办?队列是立即执行下一个任务,还是等待当前任务完成?

对于此代码:

q.async {
    print("IN 1")
    var i = 1
    while i < 10 {
     Thread.sleep(forTimeInterval: 0.1)
     i += 1
    }
    print("OUT of 1")
}

q.async {
    print("IN 2")
}

结果是:

// IN 1 -> OUT of 1 -> IN 2 ?
// or IN 1 -> IN 2 -> OUT of 1 ?

我在 playground 中尝试了 运行 代码,但似乎 sleep(和 Thread.sleep)在 Playground 中不起作用。

In principle, a serial DispatchQueue will execute the submitted tasks one after another. But what if a context switch is triggered in one task (say, calling sleep)? Does the queue execute the next task right away, or wait for the current task to finish?

串行队列不是"serial"仅仅因为它的任务是串行提交的(事实上,大多数任务通常是,即使在并行队列上),而是因为任务保证一个接一个地完成,在他们提交的顺序。

Thread.sleep 在操场上运行良好,但您的操场提前终止执行。当控制流到达页面末尾时,Playground 的执行终止。所以像这样的异步任务只有在控制流到达页面末尾之前恰好执行时才会完成,这是不太可能的。

要让 playground 无限期地执行(直到手动终止),请使用:

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

串行队列在前一个块完成之前不会开始执行下一个块。上下文切换不会影响这一点。如果您在提交给串行队列的块中调用 sleep,这将阻塞队列,直到睡眠结束并且您的块可以恢复执行。所以你的结果将是 IN 1 -> OUT of 1 -> IN 2.

请注意,通常您不想在提交到队列的块中进行阻塞操作(如 sleep),因为这会阻塞整个线程,使 libdispatch 无法使用其他工作。 libdispatch 将根据需要启动新线程以继续工作,但它会产生多少新线程是有限制的。