在以下情况下,我想了解是否需要检查callbackQueue是否为当前队列。
请帮助我清除这些情况,以了解如果当前队列是回调队列会发生什么情况
- (void)fetchWithCallbackQueue:(dispatch_queue_t)callbackQueue
{
dispatch_async(callbackQueue, ^{
});
}
答案 0 :(得分:1)
我强烈建议您观看这些视频。然后遍历我提供的示例,然后更改代码并尽可能地使用它们。花了3年的时间我才完全熟悉iOS多线程,所以花点时间:D
观看this RWDevCon video的前3分钟,如果您愿意,还可以观看更多。
还要观看3:45,直到6:15。尽管我建议您完整观看此视频。
总结一下视频在我提到的持续时间内所要表达的观点:
线程和并发与源队列和目标有关。队列。
sync vs. async特别取决于源队列。
考虑完成工作的高速公路的源队列和目标队列。
如果您异步,那么就好比您派一辆汽车(必须运送东西)离开高速公路,然后继续让其他汽车在高速公路上行驶。
如果您同步,那么就好比您派一辆汽车(必须运送东西)离开高速公路,然后停止允许任何汽车继续行驶,直到汽车运送出所有东西为止。
想想一辆汽车以代码块的形式发送东西,开始执行并结束执行。
主队列发生的事情与串行队列发生的事情相同。它们都是串行队列。
因此,如果您已经在主线程上并分派到主线程并进行异步分派,那么您分派的所有内容都会转到队列末尾
告诉我我的意思:您认为这将以什么顺序打印?您可以在Playground中轻松对其进行测试:
DispatchQueue.main.async {
print("1")
print("2")
print("3")
DispatchQueue.main.async {
DispatchQueue.main.async {
print("4")
}
print("5")
print("6")
print("7")
}
print("8")
}
DispatchQueue.main.async {
print("9")
print("10")
}
它将打印:
1
2
3
8
9
10
5
6
7
4
为什么?
主要是因为每次您分发到main时,它将到达队列末尾。
当您已经在主队列中时,向主服务器调度是一个非常隐蔽的微妙原因,您会在应用程序的用户交互中看到许多微小的延迟。
如果使用 sync 调度到同一 serial 队列,会发生什么?
死锁!参见here
如果使用 sync 分派到相同的并发队列,则不会出现死锁。但是其他所有线程只会在您同步时等待。我已经在下面讨论了。
现在,如果您要调度到并发队列,那么如果您进行同步,就像高速公路的示例一样,整个5车道的高速公路都被阻塞,直到汽车交付为止一切。除非您正在执行.barrier
队列之类的事情并试图解决read-write问题,否则在并发队列上进行同步是没有用的。
但是,仅查看在并发队列上进行同步会发生什么情况:
let queue = DispatchQueue(label: "aConcurrentQueue", attributes: .concurrent)
for i in 0...4 {
if i == 3 {
queue.sync {
someOperation(iteration: UInt32(i))
}
} else {
queue.async {
someOperation(iteration: UInt32(i))
}
}
}
func someOperation(iteration: UInt32) {
sleep(1)
print("iteration", iteration)
}
将记录:
// '3' will ALWAYS be first, because it's chocking the entire queue.
// The rest happen concurrently. And each time you run the app, the sequence of the rest would be different, because of the nature of concurrency. But likely 4 will be closer to being completed last and 0 would be closer to being finished sooner.
iteration 3
iteration 0
iteration 2
iteration 1
iteration 4
如果您在并发队列上执行 async ,则假定您的并发线程数量有限,例如一次执行5个然后5个任务。只是每个给定的任务都将到达队列的末尾。这样做可以记录日志。您可以有多个日志线程。一个线程记录位置事件,另一个记录记录购买等。
一个很好的操场示例是:
let queue = DispatchQueue(label: "serial", attributes: .concurrent)
func delay(seconds: UInt32 ) {
queue.async {
sleep(seconds)
print(seconds)
}
}
for i in (1...5).reversed() {
delay(seconds: UInt32(i))
}
即使您先分配了5个,也可以打印
1
2
3
4
5
答案 1 :(得分:1)
在您使用dispatch_async
(或在Swift中仅为async
)的示例中,没关系。分派的块将被简单地添加到相关队列的末尾,并在该队列可用时异步运行。
但是,如果您使用了dispatch_sync
(在Swift中又名sync
),那么如果您从串行队列中分派回自己,则会突然出现问题。通过从串行队列到其自身的“同步”调度,代码将“死锁”。 (并且因为主队列是串行队列,所以从主队列到其自身的同步分派也表现出相同的问题。)dispatch_sync
说:“阻塞当前线程,直到指定的队列完成运行此分派的代码为止”,因此显然任何串行队列都将同步分派回自身,它无法继续进行,因为它阻塞了您已分派要运行代码的队列。
请注意,如果您等待,则任何阻塞的GCD API(例如dispatch_semaphore_wait
和dispatch_group_wait
(在Swift中都简称为wait
),都会遇到与同步调度相同的问题串行队列使用的相同线程。
但是,在您的情况下,使用dispatch_async
异步分发 ,您应该不会有任何问题。