i saw this thread Swift 5.5 Concurrency: how to serialize async Tasks to replace an OperationQueue with maxConcurrentOperationCount = 1? but i am not clear on whether two scheduled Tasks will execute serially. What i mean is, if i had a piece of code
func fetchImages() {
Task.init {
let fetch = await loadImages()
}
Task.init {
let fetch1 = await loadImages1()
}
}
will first task always finish before second task starts? The application i am trying to get is to execute task 1 as soon as possible (save time) but task 2 relies on the result of task 1 so it needs to wait for task 1 to finish before proceeding. Task 2 also is only conditionally triggered upon an event so they cannot be in the same Task.
You asked:
will first task always finish before second task starts?
No, it will not. Whenever you see await, that is a “suspension point” at which Swift concurrency is free to switch to another task. In short, these can run concurrently. Let me illustrate that with Xcode Instruments:
import os.log
private let poi = OSSignposter(subsystem: "Test", category: .pointsOfInterest)
class Foo {
func fetchImages() {
Task {
let fetch = await loadImages()
print("done loadImages")
}
Task {
let fetch1 = await loadImages1()
print("done loadImages1")
}
}
func loadImages() async {
// start “points of interest” interval
let state = poi.beginInterval(#function, id: poi.makeSignpostID(), "start")
// await some 3-second asynchronous task
try? await Task.sleep(for: .seconds(3))
// end “points of interest” interval
poi.endInterval(#function, state, "end")
}
func loadImages1() async {
// start “points of interest” interval
let state = poi.beginInterval(#function, id: poi.makeSignpostID(), "start")
// await some 1-second asynchronous task
try? await Task.sleep(for: .seconds(3))
// end “points of interest” interval
poi.endInterval(#function, state, "end")
}
}
Profiling (in Xcode, either press command-i or choose from the menu, “Product” » “Profile”) this with the “time profiler” in Instruments, you can see that these run concurrently:

The trick is to have the second task await the first one. E.g.,
func fetchImages() {
let firstTask = Task {
let fetch = await loadImages()
print("done loadImages")
}
Task {
_ = await firstTask.result
let fetch1 = await loadImages1()
print("done loadImages1")
}
}
Or you can store the first task in some property:
var firstTask: Task<Void, Never>? // you may need to adjust the `Success` and `Failure` types to match your real example
func fetchImages() {
firstTask = Task {
let fetch = await loadImages()
print("done loadImages")
}
Task {
_ = await firstTask?.result
let fetch1 = await loadImages1()
print("done loadImages1")
}
}
When you do that, you can see the sequential execution:

FWIW, this concept, of using await on the prior task was the motivating idea behind that other answer that you referenced. That is a more generalized rendition of the above. Hopefully this illustrates the mechanism outlined in that other answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With