为什么我们需要在另一个队列上使用 dispatch_sync() 而不是在 iOS GCD 中使用当前的 queue/thread
Why we need dispatch_sync() on another queue instead of using the current queue/thread in iOS GCD
我读到 dispatch_sync()
会阻塞当前线程并且不会 return 返回它,直到一个人想要同步执行的任务在 [=13] 的串行队列上完成=] 需要继续努力。
所以基本上它会停止当前线程并执行它的任务。
如果是这样,为什么还要为这种任务设置另一个队列,为什么我们不能把任务放在当前线程上。
毕竟,执行任务无论如何都会阻塞当前线程。
既然dispatch_sync()
不会开另一个线程,那为什么我们还要开另一个队列来做任务而不是在当前queue/thread上做呢?
希望我在这里清楚地描述我的困惑。
我在这里比较在另一个队列上使用dispatch_sync()
和直接使用当前thread/queue,所以我想知道的是在什么用例中,在另一个队列上使用 dispatch_sync()
会比仅使用当前队列更好。
这应该与 thread-safe
和 synchronization
问题相关。
您想要这样做的原因可能有很多,但一个常见的用例是保护代码的关键部分。假设您有多个线程想要更新一个数组。数组不是线程安全的,因此这可能导致数组损坏。
通过对串行队列使用 dispatch_sync
并更新分派块内的数组,您可以确保一次只有一个线程更新数组。您需要同步分派,因为您希望请求线程在继续之前等待数组更新。
例如,这里有一个简单的队列class,它使用串行调度队列来确保底层数组更新时的线程安全:
class Queue<T> {
private var theQueue = [T]()
private var dispatchQ = dispatch_queue_create("queueQueue", DISPATCH_QUEUE_SERIAL);
func enqueue(object:T) {
dispatch_sync(self.dispatchQ) {
self.theQueue.append(object)
}
}
func dequeue() -> T? {
return self.dequeue(true)
}
func peek() -> T? {
return self.dequeue(false)
}
private func dequeue(remove: Bool) -> T? {
var returnObject: T?
dispatch_sync(self.dispatchQ) {
if !self.theQueue.isEmpty {
returnObject = self.theQueue.first
if (remove) {
self.theQueue.removeFirst()
}
}
}
return returnObject
}
func isEmpty() -> Bool {
return self.theQueue.isEmpty
}
}
dispatch_sync()
基本上会阻塞当前线程,直到它的所有任务都完成 - 正确!
为什么我们有像dispatch_async()
这样的其他方法是因为在某些情况下,我们需要并行执行一些任务,或者至少"near parallelism"。假设您需要通过网络下载大量文件。如果我们要在主线程上执行此操作,那么所有 UI 将冻结,直到下载完成。这是因为,UI需要不断的绘制,才能很好的保持用户体验!您不希望在单击下载按钮时看到冻结的 UI。你呢?
在这种情况下,我们可以使用 dispatch_async() 以便网络任务(下载文件)在不同的线程上执行。现在,与上述情况不同,处理器会非常快速地从下载文件切换到更新 UI。因此,应用程序将保持响应。换句话说,您将能够使用具有良好用户体验的应用程序。
希望您清楚为什么我们需要主队列以外的队列!
我读到 dispatch_sync()
会阻塞当前线程并且不会 return 返回它,直到一个人想要同步执行的任务在 [=13] 的串行队列上完成=] 需要继续努力。
所以基本上它会停止当前线程并执行它的任务。
如果是这样,为什么还要为这种任务设置另一个队列,为什么我们不能把任务放在当前线程上。
毕竟,执行任务无论如何都会阻塞当前线程。
既然dispatch_sync()
不会开另一个线程,那为什么我们还要开另一个队列来做任务而不是在当前queue/thread上做呢?
希望我在这里清楚地描述我的困惑。
我在这里比较在另一个队列上使用dispatch_sync()
和直接使用当前thread/queue,所以我想知道的是在什么用例中,在另一个队列上使用 dispatch_sync()
会比仅使用当前队列更好。
这应该与 thread-safe
和 synchronization
问题相关。
您想要这样做的原因可能有很多,但一个常见的用例是保护代码的关键部分。假设您有多个线程想要更新一个数组。数组不是线程安全的,因此这可能导致数组损坏。
通过对串行队列使用 dispatch_sync
并更新分派块内的数组,您可以确保一次只有一个线程更新数组。您需要同步分派,因为您希望请求线程在继续之前等待数组更新。
例如,这里有一个简单的队列class,它使用串行调度队列来确保底层数组更新时的线程安全:
class Queue<T> {
private var theQueue = [T]()
private var dispatchQ = dispatch_queue_create("queueQueue", DISPATCH_QUEUE_SERIAL);
func enqueue(object:T) {
dispatch_sync(self.dispatchQ) {
self.theQueue.append(object)
}
}
func dequeue() -> T? {
return self.dequeue(true)
}
func peek() -> T? {
return self.dequeue(false)
}
private func dequeue(remove: Bool) -> T? {
var returnObject: T?
dispatch_sync(self.dispatchQ) {
if !self.theQueue.isEmpty {
returnObject = self.theQueue.first
if (remove) {
self.theQueue.removeFirst()
}
}
}
return returnObject
}
func isEmpty() -> Bool {
return self.theQueue.isEmpty
}
}
dispatch_sync()
基本上会阻塞当前线程,直到它的所有任务都完成 - 正确!
为什么我们有像dispatch_async()
这样的其他方法是因为在某些情况下,我们需要并行执行一些任务,或者至少"near parallelism"。假设您需要通过网络下载大量文件。如果我们要在主线程上执行此操作,那么所有 UI 将冻结,直到下载完成。这是因为,UI需要不断的绘制,才能很好的保持用户体验!您不希望在单击下载按钮时看到冻结的 UI。你呢?
在这种情况下,我们可以使用 dispatch_async() 以便网络任务(下载文件)在不同的线程上执行。现在,与上述情况不同,处理器会非常快速地从下载文件切换到更新 UI。因此,应用程序将保持响应。换句话说,您将能够使用具有良好用户体验的应用程序。
希望您清楚为什么我们需要主队列以外的队列!