GCD 中的 Dispatch_barrier_async 和串行队列,它们之间有啥区别?

Posted

技术标签:

【中文标题】GCD 中的 Dispatch_barrier_async 和串行队列,它们之间有啥区别?【英文标题】:Dispatch_barrier_async and serial queue in GCD, what're differences between them?GCD 中的 Dispatch_barrier_async 和串行队列,它们之间有什么区别? 【发布时间】:2017-02-09 17:00:36 【问题描述】:

我发现dispatch_barrier_async的工作机制是只有在之前加入队列的所有块都完成后才会执行。它的工作方式类似于串行队列。

因此,我不区分这两种运行模式在GCD中有什么区别。

【问题讨论】:

【参考方案1】:

dispatch_barrier_[a]sync 用于并发队列。它们还应与对dispatch_[a]sync 的调用一起使用。

常见的用法是“多位读者,一位作者”模式。您设置了一个并发队列。对于“阅读器”块,您使用dispatch_[a]sync。对于“作家”块,您使用dispatch_barrier_[a]sync

此设置允许并发读取,但一次只允许一个写入器,并且在写入发生时不允许读取。

将此与一次只能发生一个块的串行队列进行比较。

【讨论】:

【参考方案2】:

您的图表完美地说明了障碍的工作原理。七个块已被分派到并发队列,四个没有障碍(图中的块 0 到 3),一个有障碍(图中的栗色“障碍块”编号为 4),然后还有两个没有障碍的块障碍(图中的块 5 和 6)。

如您所见,前四个同时运行,但障碍块在前四个完成之前不会运行。而后两个要等到“屏障”完成后才会开始。

将其与串行队列进行比较,其中没有任何任务可以同时运行:

如果分派到并发队列的每个块都使用屏障分派,那么您是对的,这相当于使用串行队列。但是,只有当您将屏障调度的块与并发队列上的非屏障调度的块结合起来时,屏障的力量才会发挥作用。所以,当你想享受并发行为时,不要使用障碍。但是,如果单个块需要在并发队列上进行类似串行的行为,请使用屏障。

一个例子是,您可以分派 10 个没有障碍的块,然后添加第 11 个带障碍的块。因此,前 10 个可能彼此同时运行,但第 11 个只会在前 10 个完成时开始(实现“完成处理程序”行为)。

或者正如 rmaddy 所说 (+1),屏障的另一个常见用途是访问一些共享资源,您将允许并发读取(无屏障),但必须强制执行同步写入(使用屏障)。在这种情况下,您通常使用dispatch_sync 进行读取,使用dispatch_barrier_async 进行写入。

【讨论】:

【参考方案3】:

#swift5

它们都用于同步, 所以串行队列确保你所有的工作都在一个堆栈中完成 例如,如果您有 A、B、C、D 任务,如果它们是同步或异步的,它们将按相同的顺序执行 在同步块完成之前,同步会阻止其他操作执行。

障碍:允许您在堆栈中执行同步操作,但它允许您执行异步操作以读取这些值,因此 在数据结构实现方面它更强大 你只有一个作家和多个读者。

func asyncReading() 
    DispatchQueue.global(qos: .background)
        .async(group: .init(), qos: .background, flags: .barrier) 
            /// Read code.
        


func syncWriting() 
    DispatchQueue.global(qos: .background)
        .sync(group: .init(), qos: .background, flags: .barrier) 
            /// Write code.
        

【讨论】:

你要再解释一下吗?不推荐纯代码答案... 当然,我会用解释更新我的答案,我假设人们阅读了其他答案。谢谢。 那么,也许,只是引用他们的重要部分。但也喜欢.sync(group: .init() 是什么,没有其他答案。

以上是关于GCD 中的 Dispatch_barrier_async 和串行队列,它们之间有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

GCD 中的“全局队列”和“主队列”有啥区别?

IOS中的多线程之GCD

GCD 中的并发队列与串行队列

Ios小白必知的GCD术语

iOS开发中的gcd多线程tips

我写的由 GCD 代码支持的读写器锁导致并行测试中的死锁