此代码将死锁,因为:
例如:
DispatchQueue.main.async {
print(Thread.current)
DispatchQueue.main.sync {
print(Thread.current)
print(2)
}
print(3)
}
为什么concurrentQueue
中不会导致死锁?它们也处于同一线程中。
DispatchQueue.global().async {
print(Thread.current)
DispatchQueue.global().sync {
print(Thread.current)
print(2)
}
print(3)
}
答案 0 :(得分:0)
您问:
为什么
concurrentQueue
中不会导致死锁?它们也处于同一线程中。
否,它们必须在同一线程中。它们位于相同的队列中,但不一定是相同的 thread。(作为优化的一部分,请参见下文,它实际上可能最终在同一线程上运行,但不一定如此。但是从逻辑上讲,您应该将其视为在单独的线程上运行。)
这是“并发队列”背后的全部思想,即它们可以在不同的线程上运行单独的调度任务。这就是它们允许并发操作的方式。并发队列上的一个调度任务可以在一个线程上运行,而同一队列上的另一调度任务可以在单独的线程上运行。
就像旧的Concurrency Programming Guide在其“并发队列”的定义中所说的:
当前正在执行的任务在分派队列管理的不同线程上运行。
或者,作为DispatchQueue
documentation says:
DispatchQueue
管理工作项的执行。提交到队列的每个工作项都在系统管理的线程池中进行处理。 [强调]
这让您更加困惑的是,如果您是dispatching synchronously ...
,则可以进行GCD优化。作为性能优化,此函数在可能的情况下在当前线程上执行块...
因此,当从队列中同步调度时,实际上 最终可以在同一线程上运行该代码(除非您是从后台队列向主队列调度)。考虑:
let queue = DispatchQueue.global()
let queue2 = DispatchQueue(label: "queue2")
queue.async {
print(1, Thread.current)
queue2.sync {
print(2, Thread.current)
}
print(3, Thread.current)
}
第二条print
语句将显示,即使您有一个完全不同的队列,作为上述sync
优化的一部分,它也可以在当前线程上运行代码。如果内部sync
调用是与派发外部块的那个queue
相同的,则同样如此。
现在,当查看优化结果时,感觉就像是串行队列方案,但事实并非如此。串行队列一次只允许运行一个调度的任务,因此,按照定义,同步调度(阻塞当前线程,直到调度的块运行)的尝试本身就是一个死锁。
但是,尽管由于进行了sync
优化,并发队列本身并没有死锁,但最终可能会在同一线程上运行代码。