Synchronizing Async Code
With DispatchGroup and DispatchSemaphore
Let say you need to perform multiple network calls and need to wait for them to complete to aggregate results.
I think the simplest solution would be to use
DispatchGroup (if the order of execution doesn’t matter) or
I will demonstrate both the problem and its solutions by using a function which will combine two async calls and then using a loop containing async calls.
Let’s create a command-line project.
Create a function which will convert Int to String after a pre-defined delay.
The First Scenario Without a Loop
Create a function which will combine two async calls:
When we run it, the output will be empty because
completionHandler is called before the
fetchData completion handlers are executed.
The first solution (without persisting the order of execution) is to use
If we run this function now, the output will be “10” because the second
fetchData takes less time complete than the first
fetchData. This could be what we want (when we don’t care about the order of execution), but we might want the second
fetchData to be called after the first one completes.
Solution for this scenario is to use
Now when we call this function the output will always be “01” regardless of how long any of the
fetchData functions take to finish.
It’s important to remember that we can’t use semaphore on the main thread because it will block it forever.
The Second Scenario Using a Loop
fetchData function in the loop passing random delay time:
If we execute this code, the output will be:
This is because
print(“text:”, text) is called before any of the
fetchData calls returned callbacks.
Let’s add synchronization:
The output now will be random, for example:
1 - 6 - 16 - 15 - 13 - 0 - 10 - 14 - 9 - 7 - 17 - 19 - 3 - 8 - 18 - 4 - 11 - 2 - 12 - 5 -
The reason is all of the
fetchData functions inside the loop will be called simultaneously, and after all callbacks complete and send
group.notify() will be executed.
DispatchSemaphore to serialize the execution inside the loop:
fetchData function will wait for previous to finish before executing and the result is:
0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 -
To recap, we have two tools for synchronizing async functions, if we just want to wait for all of them to finish we’d use
DispatchGroup, if we want them to finish and execute in the order we’d use