并发队列中的 DispatchQueue 同步与同步屏障

Vin*_*hod 9 concurrency shared-memory grand-central-dispatch swift

我正在通过 DispatchQueue 障碍,并注意到有两种方法async(flags: .barrier)sync(flags: .barrier)

我理解异步屏障的使用,但与同步屏障混淆。

我的困惑我想做的任务也可以用这个来执行

DispatchQueue.global().sync {

}
Run Code Online (Sandbox Code Playgroud)

那么同步屏障有什么用呢?为什么使用它们?这有多么不同。

DispatchQueue.global().sync(flags: .barrier) {

}
Run Code Online (Sandbox Code Playgroud)

Lut*_*utz 19

这里有两件不同的事情需要考虑:

Sync/Asyc决定提交队列上的程序流程: Usingsync()导致提交队列上的执行阻塞,直到任务完成;相比之下, usingasync()不会阻塞。

但是,使用flag.barrier会影响块在它们提交到的队列上执行的方式(显然,这只会对并发队列产生影响):

使用此标志提交的块将充当屏障:在屏障之前提交的所有其他块将完成,然后屏障块才会执行。在屏障完成之前,所有在屏障之后提交的块都不会启动。

注意:屏障标志对全局队列没有影响。您必须创建自己的并发队列才能使用屏障块。(感谢 Rob 明确指出这一点!)


Rob*_*Rob 15

Lutz 说(+1),sync/async和障碍是两个完全不同的问题。该sync/async使然的调用线程的行为(即做它等待与否)。障碍决定了它被分派到的队列的行为(是否允许它与任何其他分派到该队列的块同时运行)。

但是请注意,障碍不适用于全局队列;它们只影响您创建的私有并发队列。正如文档所说的障碍:

您指定的队列应该是您自己创建的并发队列...如果您传递给此函数的队列是串行队列或全局并发队列之一,则此函数的行为[就好像它是在没有屏障的情况下分派的]。

  • @HudiIlfeld 全局队列是共享的。您并不是唯一一个可能利用这些队列的人。您的应用程序中的其他子系统可能正在使用它们。操作系统也可能如此。障碍是一种阻塞操作,如果它们开始阻塞不相关的系统,可能会产生严重影响。对我来说,GCD 可以防止一个子系统中的一小部分代码阻塞所有其他完全不相关的子系统,这似乎非常谨慎。 (8认同)
  • 但为什么屏障不影响全局并发队列呢?它们与受障碍影响的普通私有并发队列有什么不同?有什么想法吗? (2认同)

Lea*_*ner 9

在分配障碍同步任务之前分配的任务(同步/异步)将首先完成。然后屏障同步任务将被独占执行,因为它是一个同步任务,在它完成之前不会启动其他任务。

具有屏障/非屏障同步和异步的示例并发队列示例。

let dispatchQueueA = DispatchQueue(label: "A", attributes: .concurrent)

dispatchQueueA.async { // Task1
    for index in 0 ..< 5 {
        sleep(2)
        print("Task 1 - async \(index)")
    }
}

dispatchQueueA.sync { // Task2
    for index in 0 ..< 5 {
        sleep(1)
        print("Task 2 - sync without barrier \(index)")
    }
}

dispatchQueueA.sync(flags: .barrier) { // Task3
    // the tasks(sync, async) assigned before this block will be completed first
    // then this task will execute and as it is sync task no other task will start until it finishes
    for index in 0 ..< 5 {
        sleep(1)
        print("Task 3 - sync with barrier \(index)")
    }
}

dispatchQueueA.async { // Task4
    for index in 5 ..< 10 {
        sleep(1)
        print("Task 4 - async \(index)")
    }
}

dispatchQueueA.sync { // Task5
    for index in 5 ..< 10 {
        sleep(1)
        print("Task 5 - sync without barrier \(index)")
    }
}
Run Code Online (Sandbox Code Playgroud)

上述代码的输出 - Task3(同步屏障)Task1Task2完成后执行。完成Task3(sync barrier) 后,下一个分配的任务(Task4,Task5) 已经开始。

Task 2 - sync without barrier 0
Task 1 - async 0
Task 2 - sync without barrier 1
Task 2 - sync without barrier 2
Task 2 - sync without barrier 3
Task 1 - async 1
Task 2 - sync without barrier 4
Task 1 - async 2
Task 1 - async 3
Task 1 - async 4
Task 3 - sync with barrier 0
Task 3 - sync with barrier 1
Task 3 - sync with barrier 2
Task 3 - sync with barrier 3
Task 3 - sync with barrier 4
Task 5 - sync without barrier 5
Task 4 - async 5
Task 5 - sync without barrier 6
Task 4 - async 6
Task 5 - sync without barrier 7
Task 4 - async 7
Task 5 - sync without barrier 8
Task 4 - async 8
Task 5 - sync without barrier 9
Task 4 - async 9
Run Code Online (Sandbox Code Playgroud)

  • @G.Abhisek 您不能在全局队列中使用 .barrier 标志。您需要创建自己的队列。 (3认同)