Search code examples
swiftasync-awaitconcurrency

Difference between "async let" and "async let await"


I know that we wait with await and execute a task without need to wait with async let, but I can't understand the difference between these two calls:

async let resultA = myAsyncFunc()
async let resultB = await myAsyncFunc()

In my experiment, both of these seem to behave exactly the same, and the await keyword does not have any effects here, but I'm afraid I'm missing something.

Thanks in advance for explanation on this. đŸ™đŸ»


Update

I'm adding a working sample so you can see the behavior

func myAsyncFuncA() async -> String {
    print("A start")
    try? await Task.sleep(for: .seconds(6))
    return "A"
}

func myAsyncFuncB() async -> String {
    print("B start")
    try? await Task.sleep(for: .seconds(3))
    return "B"
}

async let resultA = myAsyncFuncA()
async let resultB = await myAsyncFuncB()
print("Both have been triggered")
await print(resultA, resultB)

Results:

A start                   // Immediately
B start                   // Immediately
Both have been triggered  // Immediately
A B                       // After 6 seconds

So as you can see, resultA does not block the context and the total waiting time is the biggest waiting time.


Solution

  • You asked what is the “difference between ‘async let’ and ‘async let await’”. There is none.

    The await is unnecessary at this point and is generally omitted. One can argue that in async let x = await 
 declaration, the await would best be omitted, to avoid confusion, because it does not actually await at that point.

    So, the behavior you outline in your revision to your question is correct.

    async let resultA = myAsyncFuncA()       // execution of this current task is not suspended
    async let resultB = await myAsyncFuncB() // execution is also not suspended here
    print("Both have been triggered")        // we can see this before the above two child tasks finish
    await print(resultA, resultB)            // only here is this task suspended, awaiting those two child tasks
    

    When resultA and resultB are declared with async let, the respective asynchronous child tasks will be created, but the current task will not be suspended (notably, despite the await in async let resultB = await 
). Execution of the current task continue to proceed to the subsequent lines, after those two initializations, while A and B run concurrently. Execution will not actually await the results until you hit the await on the fourth line, the await print(
). The await in the second line, where you async let resultB = await 
, does not actually await it.

    In SE-0317 – async let bindings, they say that the “initializer of a async let permits the omission of the await keyword”. Describing this as “permits” is an understatement; we practically always omit the await at the point of initialization.