为什么我们需要在另一个队列上使用dispatch_sync()而不是在iOS GCD中使用当前队列/线程

时间:2022-06-29 21:05:04

I read that dispatch_sync() would block the current thread and won't return back to it until the task that one would like to do synchronously was finished on a serial queue that dispatch_sync() requires to work on.

我读到dispatch_sync()会阻塞当前线程,并且在dispatch_sync()需要处理的串行队列上完成一个想要同步执行的任务之前,它不会返回给它。

So basically it would stop the current thread and perform the task it has.

所以基本上它会停止当前线程并执行它具有的任务。

If that, why bother having another queue for this kind of task, why cannot we just put the task on the current thread.

如果是这样,为什么还要为这种任务打扰另一个队列,为什么我们不能把任务放在当前线程上。

After all, doing the task would block the current thread anyway.

毕竟,执行任务会阻止当前线程。

Since dispatch_sync() wouldn't open another thread, then why do we bother opening another queue to do the task rather than doing it on the current queue/thread?

由于dispatch_sync()不会打开另一个线程,那么为什么我们打扰另一个队列来执行任务而不是在当前队列/线程上执行它?

Hope I describe my confusion here clearly.

希望我能在这里清楚地描述我的困惑。

I am here comparing using dispatch_sync() on another queue with using the current thread/queue directly, so what I would like to know is in what use case, using dispatch_sync() on another queue would be better than using only the current queue.

我在这里比较使用另一个队列上的dispatch_sync()直接使用当前线程/队列,所以我想知道的是在什么用例中,在另一个队列上使用dispatch_sync()比仅使用当前队列更好。

This should be relevant to thread-safe and synchronization issue.

这应该与线程安全和同步问题相关。

2 个解决方案

#1


2  

There could be many reasons why you would want to do this, but one common use case is to guard a critical section of code. Say you have multiple threads that want to update an array. Arrays aren't thread safe so this could lead to the array becoming corrupted.

您可能有很多理由想要这样做,但一个常见的用例是保护代码的关键部分。假设您有多个要更新阵列的线程。数组不是线程安全的,因此可能导致数组损坏。

By using a dispatch_sync on to a serial queue and updating the array inside the dispatched block you can ensure that only one thread updates the array at a time. You need a synchronous dispatch because you want the requesting thread to wait until the array has been updated before continuing.

通过将dispatch_sync用于串行队列并更新调度块内的数组,可以确保一次只有一个线程更新阵列。您需要一个同步调度,因为您希望请求线程等到阵列更新后再继续。

For example, here is a simple queue class that uses a serial dispatch queue to ensure thread safety when the underlying array is updated:

例如,这是一个简单的队列类,它使用串行调度队列来确保更新基础数组时的线程安全性:

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
    }
}

#2


0  

dispatch_sync() would basically block the current thread until all it's tasks are done-Correct!

dispatch_sync()基本上会阻塞当前线程,直到完成所有任务 - 正确!

Why we have other methods like dispatch_async() is because in certain situations, we need to execute some tasks with parallelism or at least "near parallelism". Suppose you need to download a substantial file over the network. If we're to do this on the main thread, then all the UI will freeze until the download finishes. This is because, the UI needs to be drawn continuously so that the user experience is maintained well! You wouldn't like to see a frozen UI whenever you click a download button. Do you?

为什么我们有其他方法,如dispatch_async()是因为在某些情况下,我们需要执行一些并行或至少“接近并行”的任务。假设您需要通过网络下载实质文件。如果我们要在主线程上执行此操作,那么所有UI都将冻结,直到下载完成。这是因为,需要连续绘制UI,以便保持良好的用户体验!单击下载按钮时,您不希望看到冻结的UI。你做?

In such cases, we can use dispatch_async() so that the network task (downloading the file) gets executed on a different thread. Now, unlike the above case, the processor would very quickly switch from downloading the file to updating the UI. Therefore, the app will remain responsive. In other words, you will be able to use the app with good user experience.

在这种情况下,我们可以使用dispatch_async(),以便在不同的线程上执行网络任务(下载文件)。现在,与上述情况不同,处理器可以非常快速地从下载文件切换到更新UI。因此,该应用程序将保持响应。换句话说,您将能够使用具有良好用户体验的应用程序。

Hope you're clear on why we need queues other than the main queue!

希望你清楚为什么我们需要除主队列之外的队列!

#1


2  

There could be many reasons why you would want to do this, but one common use case is to guard a critical section of code. Say you have multiple threads that want to update an array. Arrays aren't thread safe so this could lead to the array becoming corrupted.

您可能有很多理由想要这样做,但一个常见的用例是保护代码的关键部分。假设您有多个要更新阵列的线程。数组不是线程安全的,因此可能导致数组损坏。

By using a dispatch_sync on to a serial queue and updating the array inside the dispatched block you can ensure that only one thread updates the array at a time. You need a synchronous dispatch because you want the requesting thread to wait until the array has been updated before continuing.

通过将dispatch_sync用于串行队列并更新调度块内的数组,可以确保一次只有一个线程更新阵列。您需要一个同步调度,因为您希望请求线程等到阵列更新后再继续。

For example, here is a simple queue class that uses a serial dispatch queue to ensure thread safety when the underlying array is updated:

例如,这是一个简单的队列类,它使用串行调度队列来确保更新基础数组时的线程安全性:

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
    }
}

#2


0  

dispatch_sync() would basically block the current thread until all it's tasks are done-Correct!

dispatch_sync()基本上会阻塞当前线程,直到完成所有任务 - 正确!

Why we have other methods like dispatch_async() is because in certain situations, we need to execute some tasks with parallelism or at least "near parallelism". Suppose you need to download a substantial file over the network. If we're to do this on the main thread, then all the UI will freeze until the download finishes. This is because, the UI needs to be drawn continuously so that the user experience is maintained well! You wouldn't like to see a frozen UI whenever you click a download button. Do you?

为什么我们有其他方法,如dispatch_async()是因为在某些情况下,我们需要执行一些并行或至少“接近并行”的任务。假设您需要通过网络下载实质文件。如果我们要在主线程上执行此操作,那么所有UI都将冻结,直到下载完成。这是因为,需要连续绘制UI,以便保持良好的用户体验!单击下载按钮时,您不希望看到冻结的UI。你做?

In such cases, we can use dispatch_async() so that the network task (downloading the file) gets executed on a different thread. Now, unlike the above case, the processor would very quickly switch from downloading the file to updating the UI. Therefore, the app will remain responsive. In other words, you will be able to use the app with good user experience.

在这种情况下,我们可以使用dispatch_async(),以便在不同的线程上执行网络任务(下载文件)。现在,与上述情况不同,处理器可以非常快速地从下载文件切换到更新UI。因此,该应用程序将保持响应。换句话说,您将能够使用具有良好用户体验的应用程序。

Hope you're clear on why we need queues other than the main queue!

希望你清楚为什么我们需要除主队列之外的队列!