The original address: ali-akhtar.medium.com/concurrency…

This is the second part of the Swift concurrent programming series. This section describes the Dispatch Group.

The Dispatch Group has the following characteristics:

  1. The Dispatch Group can block threads until one or more tasks complete and continue down. You can use this feature to complete tasks that need to wait for other tasks to complete.

  2. After dispatching multiple tasks to calculate some data, you can use the Dispatch Group to wait for those tasks and then complete the post-processing results, although they may also run on different queues.

  3. The Dispatch Group can perform task aggregation synchronization

usewait

As shown above, we did the following:

  1. Created a custom concurrent queue labeled “com.any.app. queue”
  2. A scheduling group is created
  3. usegroup.enter()Enter groups manually Note: the call to this function must be made withgroup.leave()Balance, or the application will crash
  4. throughqueue.asyncPerform task 1, which will return immediately and GCD will start running the task concurrently
  5. Again usinggroup.enter()Manually added to the group
  6. throughqueue.asyncPerform task 2, again, it will return immediately and GCD will start running the task concurrently
  7. group.wait()Will block any thread here until all of the above tasks are complete (so don’t use this function on the main thread), since we called this method on the main thread, it will block the main thread.

To avoid blocking the main thread, we can wait on background threads like this:

usenotify

In the previous section, we used queue asynchronous dispatch to avoid blocking the main thread, but that didn’t seem optimal. Because it always blocks a thread. Fortunately, the COMMUNIST Party of China offers a better solution to usenotifyYou can be notified when all tasks are complete:

In the example below, #3 FINISHED is printed after tasks 1 and 3 are complete, but it does not wait for task 2 to complete. Because task 2 is not executed in the group.

After our transformation,#3 finishedWill be printed after all tasks are completed:

DispatchGroup.notify(qos:flags:queue:execute:)Receiving a parameterqueueTo determine on which queue the completed task will be executed. If we specify the main queue, it will execute on the main thread:

barrier

  1. Dispatch barriersIs a set of andConcurrent queueFunctions that work together and provide similarserialThe ability to perform tasks.
  2. When you submit a DispatchWorkItem (task) to a dispatch queue, you can set flags to indicate that it should be the only task to execute on a given queue at a particular time. This means that inDispatch barrierAll tasks submitted to the queue before a task must be completed before it begins execution.

For the above example:

  1. Create a concurrent queue
  2. Task 1 and task 2 are dispatched asynchronously
  3. At this point, the above two tasks are executed concurrently. In this case we usebarrierAdd task 3 as a sign that it will start executing after all previous tasks have completed, and no other tasks will be executed during task 3.
  4. Continue adding task 4, which will be inbarrierTask after execution

The results are as follows:

We use thebarrierThe assigned tasks are independent in the concurrent queueserialThe method is executed. Like this:

Read and write questions

If you read and write on multiple threads, you are bound to run into read and write problems. The Dispatch barrier can be used to implement the multi-read single-write model:

class ReadWriteSolution {
  /// Dependent concurrent queue
  let queue = DispatchQueue(label: "com.queue.rw", attributes: .concurrent)
  
  private var _file = 0
  var file: Int {
    get {
      // Read operations need to be returned synchronously
      queue.sync {
        return _file
      }
    }
    set {
      // Write operations need to be separated from other writes or reads
      queue.async(flags: .barrier) { [self] in
        self._file = newValue
      }
    }
  }
}
Copy the code