了解dispatch_queues和同步/异步调度

加布·塞尚(Gabe Sechan)

我是一位Android工程师,试图移植一些使用5个SERIAL调度队列的iOS代码。我想确保我以正确的方式思考问题。

  • 基本上,将SERIAL_SYNC分配到SERIAL队列是将队列用作同步队列-只有一个线程可以访问它,并且可以将执行的块视为关键区域。它立即在当前线程上发生-相当于

    get_semaphore()
    queue.pop()
    do_block()
    release_semaphore()
    
  • 到串行队列的dispatch_async-在另一个线程上执行该块,并让当前线程立即返回。但是,由于它是一个串行队列,因此它保证这些异步线程中的一个只会一次执行(下一次对dispatch_async的调用将等待,直到所有其他线程完成)。该块也可以被视为关键区域,但是它将发生在另一个线程上。因此,代码与上述相同,但首先将其传递给工作线程。

我有这方面的建议吗,还是我正确地找到了答案?

这感觉像是一种过于复杂的思维方式,并且该描述中有许多小细节并不完全正确。具体来说,“它立即在当前线程上发生”是不正确的。

首先,让我们退后一步:dispatch_async之间的区别dispatch_sync仅仅是当前线程是否在等待它。但是,当您将某些内容分派到串行队列时,您应该始终想象它在GCD自己选择的单独工作线程上运行。是的,作为一种优化,有时dispatch_sync会使用当前线程,但是绝对不能保证这一事实。

其次,当您讨论时dispatch_sync,您会说“立即”运行。但这绝不能保证立即生效。如果线程dispatch_sync对某个串行队列执行操作,则该线程将阻塞,直到(a)该串行队列上当前正在运行的任何块结束;(b)运行并完成该串行队列的任何其他排队的块;(c)显然,线程A本身调度的块运行并完成。

现在,当您使用串行队列进行同步时,对内存中某些对象的某些线程安全访问通常使同步过程非常快,因此,等待线程通常在其派发块中被阻塞的时间可以忽略不计(以及之前所有已分发的块)。但是总的来说,说它将立即运行会产生误导。(如果它总是可以立即运行,那么您就不需要队列来同步访问)。


现在您的问题是关于“关键区域”的,我假设您正在谈论的是一些代码,为了确保线程安全或类似的其他原因,这些代码必须同步。所以,这段代码运行时要同步,唯一的问题重新dispatch_syncVSdispatch_async是当前线程是否必须等待。例如,一种常见的模式是说,有人可以dispatch_async向某个模型写入数据(因为在继续操作之前无需等待模型更新),但是dispatch_sync却从某个模型读取数据(因为您显然不希望继续执行该操作,直到读取值返回)。

同步/异步模式的进一步优化是读取器-写入器模式,在该模式下,允许并发读取,但不允许并发写入。因此,您将使用并发队列,dispatch_barrier_async即写入(实现写入的类似串行行为),但dispatch_sync使用读取(就其他读取操作而言,享受并发性能)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章