Modern Concurrency: Beyond the Basics

Oct 20 2022 · Swift 5.5, iOS 15, Xcode 13.4

Part 2: Concurrent Code

13. Using TaskGroup

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 12. TaskGroup Next episode: 14. Actor

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

In this episode, you'll do more with a task group you created in the previous episode. You'll get and process task results and control the number of tasks running in parallel. Continue with your sky project from the previous episode or open the starter project. If using the starter project, remember to set up the signing and capabilities. Build and run on your device, and tap engage systems. The first indicator number of scheduled tasks should be more than one, and this alert message should display a fraction of 20 seconds. You can see your task group is running tasks. Now it's time to get the result of all this work, stop the run. Open scan model and locate run all tasks. Task groups can return a result that conforms to async sequence, so you can use the reduced method of async sequence. At the end of the task group closure after the four loop return a result. You use reduce to collect all the return to task values into an array of strings. X-code complains about the closure returning of value so set the closure's return type and assign the return value to scans. The task group waits for all tasks to finish before returning. If you add code below it, you can assume all the tasks have completed. So just to verify your result, add a print statement at the end of run all tasks after the task group closure. To save time build and run on your device, then tap engage systems. The task group runs tasks in whatever order makes best use of system resources, so your output probably shows a different order. Actually task group lets you dynamically manage the workload of the group during execution. So instead of returning the group's result to be used outside the group, you'll process results inside the group's closure. Undo your last four edits to remove the code that returns the group result and then uses it. Now at a second four loop at the bottom of the closure after the four number loop. Group conforms to async sequence so you iterate over its results in a loop. The loop runs as long as there are pending tasks and suspends before each iteration. It ends when the group finishes running all its tasks. Build and run on your device. Look at the output console, the runtime executes the tasks asynchronously. As soon as each task completes the four await loop runs one more time. Next, you'll look into gaining even more control over the group execution by using custom iteration logic. Instead of letting the run time decide how many tasks to execute and when, you'll tell it to run at most four at a time. In run all tasks, replace all the code in the group's closure. You set the first four tasks going exactly four, to run the rest of the tasks, you'll add a new task whenever a running task completes. Do this below the four loop. You define a starting index and set it to the batch size and add a four loop. You loop over any completing tasks and print its completed message. Now add the next task. As long as the current index is less than the total number of tasks, you add one more task to the group. You can see how flexible the task group APIs are. You iterate over the results and add fresh tasks at the same time. You control how many tasks can run at the same time and you don't need to change anything outside the task group closure because these logic changes are completely transparent to the consumer. This means you can keep a group running indefinitely by always adding more and more tasks, retry tasks by re adding them to the group upon failure. Insert a high priority UI task after either a set number of computational tasks finish running, or you find a given result. Build and run on your device. Tap engage systems. The number of scheduled tasks is always four because as soon as one completes you schedule a new one in its place. My phone used five threads before but now the second indicator shows that it completes only four tasks per second because that's how many are running. If you device used fewer than four threads before, the second indicator shows that you advance the total amount of work by only that many tasks per second. I'll change my batch size to seven to demonstrate this. You see it's running five tasks per second, not seven. I'll reset my batch size to four. After you run a task group, you usually want to do some cleanup, update the UI or do something else. In this project, you should reset some indicators when the scan is over so they don't confuse the user. You could use task group wait for all to wait for all the tasks to complete and then add the cleanup code. But the four try await loop already waits for all tasks. It only ends when the group runs out of tasks. So inside the task group closure below the four oh Await result in group loop, add this. Build and run then tap engage systems to check this. Now your app is ready to re-scan and that's how you can use task group to dynamically create concurrency in your apps. Check out the links below to see how the book handles task group errors with the result type. In this app, you didn't have to worry about data races because the tasks are all independent, but when you introduce concurrency, you must always ensure your concurrent code doesn't modify any shared state. And that's what you learn about in the rest of this course. Coming right up, actors.