Synchronizing Async Code

With DispatchGroup and DispatchSemaphore

Borama Apps
Jul 9 · 2 min read
Photo by oakie on Unsplash

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 DispatchSemaphore.

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 DispatchGroup:

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 DispatchSemaphore:

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

Call the fetchData function in the loop passing random delay time:

If we execute this code, the output will be:

text:

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.leave(), group.notify() will be executed.

Finally, add DispatchSemaphore to serialize the execution inside the loop:

Now each 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 DispatchSemahpore.

That’s it!

Better Programming

Borama Apps

Written by

ios, android, web apps. https://borama.co, http://twitter.com/boramaapps

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade