如果在同一队列中分派怎么办?

时间:2019-10-29 00:45:41

标签: ios grand-central-dispatch

在以下情况下,我想了解是否需要检查callbackQueue是否为当前队列。

请帮助我清除这些情况,以了解如果当前队列是回调队列会发生什么情况

  1. callbackQueue是队列。
  2. callbackQueue是并发队列。
  3. callbackQueue是串行队列。
- (void)fetchWithCallbackQueue:(dispatch_queue_t)callbackQueue
{
  dispatch_async(callbackQueue, ^{

  });
}

2 个答案:

答案 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_waitdispatch_group_wait(在Swift中都简称为wait),都会遇到与同步调度相同的问题串行队列使用的相同线程。

但是,在您的情况下,使用dispatch_async异步分发 ,您应该不会有任何问题。