了解 dispatch_queues 和 synchronous/asynchronous 调度
Understanding dispatch_queues and synchronous/asynchronous dispatch
我是一名 Android 工程师,试图移植一些使用 5 个串行调度队列的 iOS 代码。我想确保我以正确的方式思考问题。
dispatch_sync 到 SERIAL 队列基本上是将该队列用作同步队列 - 只有一个线程可以访问它,并且可以将执行的块视为临界区。它立即发生在当前线程上——相当于
get_semaphore()
queue.pop()
do_block()
release_semaphore()
dispatch_async 到串行队列 - 在另一个线程上执行块并让当前线程立即 return。然而,由于它是一个串行队列,它承诺一次只会执行这些异步线程中的一个(下一次调用 dispatch_async 将等待所有其他线程完成)。该块也可以被认为是临界区,但它会出现在另一个线程上。所以与上面相同的代码,但它首先传递给工作线程。
我是不是对这些有任何误解,还是我猜对了?
要挑选 nits,dispatch_sync 不一定 运行 当前线程上的代码,但如果不是,它仍然会阻塞当前线程,直到任务完成。只有在您依赖线程 ID 或 thread-local 存储时,这种区别才可能很重要。
但除此之外,是的,除非我错过了一些微妙的东西。
这感觉像是一种过于复杂的思考方式,并且该描述中有很多细节不太正确。具体来说,"it happens immediately on the current thread" 是不正确的。
首先,让我们退一步:dispatch_async
和dispatch_sync
之间的区别仅仅是当前线程是否等待它。但是,当您将某些内容分派到串行队列时,您应该始终想象它在 GCD 自己选择的一个单独的工作线程上 运行ning。是的,作为一种优化,有时 dispatch_sync
会使用当前线程,但您无法保证这一点。
其次,当你讨论dispatch_sync
的时候,你说的是运行宁"immediately"。但这决不能保证立即生效。如果线程对某个串行队列执行 dispatch_sync
,则该线程将阻塞,直到 (a) 当前在该串行队列上 运行 的任何块完成; (b) 该串行队列的任何其他排队块 运行 并完成; (c) 显然,线程 A 本身调度 运行s 并完成的块。
现在,当您使用串行队列进行同步时,一些 thread-safe 访问内存中的某个对象,通常同步过程非常快,因此等待线程通常会被阻塞,数量可以忽略不计它的分派块(以及任何先前分派的块)完成的时间。但总的来说,说它会立即 运行 是误导。 (如果它总是可以 运行 立即,那么你就不需要队列来同步访问)。
现在你的问题是关于 "critical region",我假设你在谈论一些代码,为了确保 thread-safety 或出于类似的其他原因,必须同步。因此,当 运行 同步此代码时, dispatch_sync
与 dispatch_async
的唯一问题是当前线程是否必须等待。例如,一个常见的模式是说可以 dispatch_async
写入某个模型(因为在继续之前不需要等待模型更新),但是 dispatch_sync
从某个模型读取(因为您显然不想在返回读取值之前继续操作)。
sync/async 模式的进一步优化是 reader-writer 模式,其中允许并发读取但不允许并发写入。因此,您将使用并发队列,dispatch_barrier_async
写入(实现 serial-like 写入行为),但 dispatch_sync
读取(享受与其他读取操作相关的并发性能)。
我是一名 Android 工程师,试图移植一些使用 5 个串行调度队列的 iOS 代码。我想确保我以正确的方式思考问题。
dispatch_sync 到 SERIAL 队列基本上是将该队列用作同步队列 - 只有一个线程可以访问它,并且可以将执行的块视为临界区。它立即发生在当前线程上——相当于
get_semaphore() queue.pop() do_block() release_semaphore()
dispatch_async 到串行队列 - 在另一个线程上执行块并让当前线程立即 return。然而,由于它是一个串行队列,它承诺一次只会执行这些异步线程中的一个(下一次调用 dispatch_async 将等待所有其他线程完成)。该块也可以被认为是临界区,但它会出现在另一个线程上。所以与上面相同的代码,但它首先传递给工作线程。
我是不是对这些有任何误解,还是我猜对了?
要挑选 nits,dispatch_sync 不一定 运行 当前线程上的代码,但如果不是,它仍然会阻塞当前线程,直到任务完成。只有在您依赖线程 ID 或 thread-local 存储时,这种区别才可能很重要。
但除此之外,是的,除非我错过了一些微妙的东西。
这感觉像是一种过于复杂的思考方式,并且该描述中有很多细节不太正确。具体来说,"it happens immediately on the current thread" 是不正确的。
首先,让我们退一步:dispatch_async
和dispatch_sync
之间的区别仅仅是当前线程是否等待它。但是,当您将某些内容分派到串行队列时,您应该始终想象它在 GCD 自己选择的一个单独的工作线程上 运行ning。是的,作为一种优化,有时 dispatch_sync
会使用当前线程,但您无法保证这一点。
其次,当你讨论dispatch_sync
的时候,你说的是运行宁"immediately"。但这决不能保证立即生效。如果线程对某个串行队列执行 dispatch_sync
,则该线程将阻塞,直到 (a) 当前在该串行队列上 运行 的任何块完成; (b) 该串行队列的任何其他排队块 运行 并完成; (c) 显然,线程 A 本身调度 运行s 并完成的块。
现在,当您使用串行队列进行同步时,一些 thread-safe 访问内存中的某个对象,通常同步过程非常快,因此等待线程通常会被阻塞,数量可以忽略不计它的分派块(以及任何先前分派的块)完成的时间。但总的来说,说它会立即 运行 是误导。 (如果它总是可以 运行 立即,那么你就不需要队列来同步访问)。
现在你的问题是关于 "critical region",我假设你在谈论一些代码,为了确保 thread-safety 或出于类似的其他原因,必须同步。因此,当 运行 同步此代码时, dispatch_sync
与 dispatch_async
的唯一问题是当前线程是否必须等待。例如,一个常见的模式是说可以 dispatch_async
写入某个模型(因为在继续之前不需要等待模型更新),但是 dispatch_sync
从某个模型读取(因为您显然不想在返回读取值之前继续操作)。
sync/async 模式的进一步优化是 reader-writer 模式,其中允许并发读取但不允许并发写入。因此,您将使用并发队列,dispatch_barrier_async
写入(实现 serial-like 写入行为),但 dispatch_sync
读取(享受与其他读取操作相关的并发性能)。