# Can someone recommend a good, modern tutorial on concurrency?

**URL:** <https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627>\
**Category:** Using Swift\
**Created:** [August 1, 2024, 6:20pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627 "2024-08-01T18:20:57Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [August 2, 2024, 1:55pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/21 "2024-08-02T13:55:24Z")

</div>

> [@dima\_kozhinov](#):
>
> And in my experience this blocks the main thread. E.g. this code

It "blocks" only because your code here is sequential (precisely what structured concurrency is about), and no other work is scheduled.

BTW, that's not allowed in Swift 6 – because in this way it actually blocks a thread. You have to use `Task.sleep` instead, which won't block:

> [@dima\_kozhinov](#):
>
> ```swift
> func asyncFunc () async {
> Thread.sleep(forTimeInterval: 5) // error
> print("async func output")
> }
> 
> ```

And then, if you'll update it properly – so that there is other work to run, it will run it:

```swift
import Foundation

func asyncFunc () async {
    try? await Task.sleep(for: .seconds(5))
    print("async func output")
}

print("will call async func")
await withDiscardingTaskGroup { group in
    group.addTask {
        await asyncFunc()
    }
    group.addTask {
        print("some other work here")
    }
}
print("did call async func")

```

Your main code at the top-level is still executes sequentially, since that's the goal after all. But sequential execution is not the same as blocking.

> [@dima\_kozhinov](#):
>
> How is this possible at all - to suspend a function and allow a caller thread do other work? Caller thread will wait for the function to return and not execute any further until function returns.

Swift saves call stack on suspension point, freeing thread for execution, and then restores when task is ready to be resumed. If Swift would block threads on each suspension point, paired with limited pool of threads it operates on, Swift Concurrency would run out of threads to execute tasks pretty easily. That's why blocking threads (and relative APIs) aren't suitable for use.

---

<div class="post-metadata">

**Author:** ![nkbelov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nkbelov/32/34617_2.png) [@nkbelov](https://forums.swift.org/u/nkbelov)\
**Post date:** [August 2, 2024, 2:06pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/22 "2024-08-02T14:06:43Z")

</div>

> [@dima\_kozhinov](#):
>
> How is this possible at all - to suspend a function and allow a caller thread do other work?

`async` functions are compiled into coroutines, which are basically state machines, where every synchronous part ("the code between `await` statements") is a separate partial synchronous function. When an `async` function suspends, one of those partial functions has finished, and the caller thread is running the runtime code at this point — the thread never pauses "inside" of the body of an async function.

Related: [https://youtu.be/wyAbV8AM9PM](https://youtu.be/wyAbV8AM9PM) and [https://youtu.be/H\_K-us4-K7s](https://youtu.be/H_K-us4-K7s)

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 2:17pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/23 "2024-08-02T14:17:47Z")

</div>

> [@vns](#):
>
> It "blocks" only because your code here is sequential

Any single thread is sequential. And `await` suspends that thread IMHO. Maybe there are cooperative tasks in Swift that run on main thread (and do not create worker threads), but that is another story.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 2:18pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/24 "2024-08-02T14:18:19Z")

</div>

> [@vns](#):
>
> that's not allowed in Swift 6 – because in this way it actually blocks a thread

Exactly what I said.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 2:24pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/25 "2024-08-02T14:24:19Z")

</div>

> [@nkbelov](#):
>
> the thread never pauses "inside" of the body of an async function

What is "the thread"? Is it a worker thread created specifically for the `async` function? Or is it a caller thread using cooperative multitasking? Either way, the `await` in the caller thread pauses its execution.

---

<div class="post-metadata">

**Author:** ![Datagram](https://avatars.discourse-cdn.com/v4/letter/d/7cd45c/32.png) [@Datagram](https://forums.swift.org/u/Datagram)\
**Post date:** [August 2, 2024, 2:26pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/26 "2024-08-02T14:26:53Z")

</div>

```swift
import Foundation

func asyncFunc () async -> Int {
    try! await Task.sleep(for: .seconds(5))
    print("async func output")
    return 100
}

print("will call async func")
async let result = asyncFunc()
print("did call async func")
print("result \(await result)")

```

will call async func  
did call async func  
async func output  
result 100  
Program ended with exit code: 0

---

<div class="post-metadata">

**Author:** ![nkbelov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nkbelov/32/34617_2.png) [@nkbelov](https://forums.swift.org/u/nkbelov)\
**Post date:** [August 2, 2024, 2:29pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/27 "2024-08-02T14:29:32Z")

</div>

"The thread" is either the main thread or one of the threads in the cooperative thread pool created by the concurrency runtime. The total number of these is typically equal to the number of CPU cores.

FWIW there _is_ a certain "task-to-thread model" that can be encountered in the runtime source, but I'm not sure where it's used (embedded perhaps?). Anyway, this is not the default behaviour.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 2:31pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/28 "2024-08-02T14:31:48Z")

</div>

> [@Datagram](#):
>
> `async let result = asyncFunc()`

This essentially creates a worker thread and continues caller thread execution. We here talking about the `await` keyword which IMHO suspends current thread, and everyone tells me otherwise.

---

<div class="post-metadata">

**Author:** ![nkbelov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nkbelov/32/34617_2.png) [@nkbelov](https://forums.swift.org/u/nkbelov)\
**Post date:** [August 2, 2024, 2:36pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/29 "2024-08-02T14:36:29Z")

</div>

> [@dima\_kozhinov](#):
>
> which IMHO suspends current thread

This is not a question of opinion :) You could either look into the [source that deals with suspension](https://github.com/swiftlang/swift/blob/f300164accb6f695e2ea507e2aa28bbec7571132/stdlib/public/Concurrency/Task.cpp#L1489) or watch the talks that specifically discuss how Swift's concurrency runtime is implemented.

> [@nkbelov](#):
>
> Related: [https://youtu.be/wyAbV8AM9PM](https://youtu.be/wyAbV8AM9PM) and [https://youtu.be/H\_K-us4-K7s](https://youtu.be/H_K-us4-K7s)

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [August 2, 2024, 2:37pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/30 "2024-08-02T14:37:35Z")

</div>

> [@dima\_kozhinov](#):
>
> > [@vns](#):
> >
> > that's not allowed in Swift 6 – because in this way it actually blocks a thread
> 
> Exactly what I said.

You say that `await` blocks, I say it does not and prohibits blocking APIs to be called as well to prevent this. Two opposite things. Blocking inside `async` function considered to be a programming error.

> [@dima\_kozhinov](#):
>
> What is "the thread"? Is it a worker thread created specifically for the `async` function? Or is it a caller thread using cooperative multitasking? Either way, the `await` in the caller thread pauses its execution.

Pauses _function_ execution. Thread itself is free to schedule any other work after suspension.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [August 2, 2024, 2:43pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/31 "2024-08-02T14:43:12Z")

</div>

> [@dima\_kozhinov](#):
>
> Either way, the `await` in the caller thread pauses its execution.

This is not the case. If we narrowly look at the main thread/queue/actor case then the following code:

```swift
func getX() async { ... }

@MainActor
func f() async -> Something {
  let x = await getX()
  return doSomething(x)
}

```

can be understood as being _roughly_ analogous so something like:

```swift
func getX(completion: (X) -> Void)) {
  DispatchQueue.global().async {
    ...
  }
}

func g(completion: (Something) -> Void) {
  getX(completion: { x in
    DispatchQueue.main.async {
      completion(doSomething(x, y)
    }
  })
}

```

(Edit: updated to relocate the move off the main thread into `getX`)

The main thread is not blocked during an `await` in `f` any more than it is blocked after the `getX` call before the `completion` parameter is called. And moreover, all of the wrangling to move work on/off the main thread is handled 'automatically' by virtue of the functions declaring where they should be run.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 3:02pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/32 "2024-08-02T15:02:11Z")

</div>

> [@vns](#):
>
> You say that `await` blocks

I say that `await` blocks the _caller_ thread.

> [@vns](#):
>
> I say it does not and prohibits blocking APIs to be called as well to prevent this.

This sounds like complete gibberish to me.

> [@vns](#):
>
> Blocking inside `async` function considered to be a programming error

First, I said that `await` blocks _caller_ thread, and not a _called_ `async` function, which runs in a separate worker thread.

Second, blocking inside `async` function cannot be a programming error. You create an `async` function to do a lengthy processing, e.g. fetching some resource from the Web. The fetch call inside the `async` function is definitely an `await` call which blocks the `async` function (in other words blocks the worker thread created specifically for the async function). The whole point of creating `async` functions (read: worker threads) is to not block the caller thread (possibly main thread), and move blocking operations into parallel threads.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [August 2, 2024, 3:10pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/33 "2024-08-02T15:10:26Z")

</div>

> [@dima\_kozhinov](#):
>
> (in other words blocks the worker thread created specifically for the async function)

A nonisolated `async` function doesn't have its own dedicated thread. Nonisolated `async` functions are serviced by the Swift Concurrency cooperative thread pool which has a limited number of threads to service jobs submitted to the pool. When an async function hits a suspension point (i.e., an `await`) it is removed from scheduling contention and the thread is freed up to run other jobs submitted to the pool until the original function is unsuspended and eligible for scheduling again.

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [August 2, 2024, 3:12pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/34 "2024-08-02T15:12:00Z")

</div>

> [@dima\_kozhinov](#):
>
> This sounds like complete gibberish to me.

So `Thread.sleep` being marked as unavailable from async is gibberish?

> [@dima\_kozhinov](#):
>
> Second, blocking inside `async` function cannot be a programming error.

I wouldn't be so sure:  
[https://forums.swift.org/t/cooperative-pool-deadlock-when-calling-into-an-opaque-subsystem/](https://forums.swift.org/t/cooperative-pool-deadlock-when-calling-into-an-opaque-subsystem/)

> [@dima\_kozhinov](#):
>
> First, I said that `await` blocks _caller_ thread, and not a _called_ `async` function, which runs in a separate worker thread.

`await` does not block any thread at all. It suspends function\[1\]. Then work is scheduled to be run on _a_ thread.

* * *

1. to be completely correct, it marks a potential suspension point, but does not determines if it will actually suspend.

---

<div class="post-metadata">

**Author:** ![Max\_Desiatov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/max_desiatov/32/20654_2.png) [@Max\_Desiatov](https://forums.swift.org/u/Max_Desiatov)\
**Post date:** [August 2, 2024, 3:53pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/35 "2024-08-02T15:53:08Z")

</div>

> [@dima\_kozhinov](#):
>
> The whole point of creating `async` functions (read: worker threads) is to not block the caller thread (possibly main thread), and move blocking operations into parallel threads.

Concurrency != multi-threading. You can easily get concurrency and `async`/`await` working in a single-threaded environment. In fact Node.js and browser environment without web workers is purely single-threaded, with `async`/`await` and coroutine transformation working similarly to what the Swift compiler does under the hood. Similarly, `async`/`await` in Python can be backed with a single-threaded event-loop, no threads are blocked by `await`.

As for Swift itself, certain platforms it targets like WASI can be single-threaded (see [`SWIFT_CONCURRENCY_GLOBAL_EXECUTOR=singlethreaded` setting](https://github.com/swiftlang/swift/blob/f300164accb6f695e2ea507e2aa28bbec7571132/stdlib/cmake/modules/StdlibOptions.cmake#L242)), and `async`/`await` works perfectly fine there, no threads are blocked, since blocking the only thread would just hang the whole program.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [August 2, 2024, 4:00pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/36 "2024-08-02T16:00:56Z")

</div>

At some point (still?) IIRC that setting was also enabled when running apps in the iOS simulator to make it _very obvious_ when you're introducing a thread-blocking dependency between tasks.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 4:30pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/37 "2024-08-02T16:30:02Z")

</div>

> [@Jumhyn](#):
>
> A nonisolated `async` function doesn't have its own dedicated thread. Nonisolated `async` functions are serviced by the Swift Concurrency cooperative thread pool

That is just implementation details. Dedicated thread or reused from a pool - either way it's a different thread.

---

<div class="post-metadata">

**Author:** ![dima\_kozhinov](https://avatars.discourse-cdn.com/v4/letter/d/258eb7/32.png) [@dima\_kozhinov](https://forums.swift.org/u/dima_kozhinov)\
**Post date:** [August 2, 2024, 4:39pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/38 "2024-08-02T16:39:53Z")

</div>

> [@vns](#):
>
> `await` does not block any thread at all. It suspends function

As I already said, any single thread is sequential. Suspending a function in a single thread means suspending the thread.

> [@vns](#):
>
> Then work is scheduled to be run on _a_ thread.

Yes. On a _different_ thread, created or reused from a pool specifically for the called `async` function. A caller thread is awaiting, that is blocked or suspended or whatever - it does not execute until the `async` function is finished.

---

<div class="post-metadata">

**Author:** ![nkbelov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nkbelov/32/34617_2.png) [@nkbelov](https://forums.swift.org/u/nkbelov)\
**Post date:** [August 2, 2024, 4:48pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/39 "2024-08-02T16:48:33Z")

</div>

> [@dima\_kozhinov](#):
>
> A caller thread is awaiting, that is blocked or suspended or whatever - it does not execute until the `async` function is finished.

There's a simple way to demonstrate that this is not what's happening:

```swift
import Foundation

@MainActor
func test() async {
    assert(Thread.isMainThread)
    await Task.yield()
    assert(Thread.isMainThread)
    try? await Task.sleep(for: .seconds(1))
    assert(Thread.isMainThread)
}

assert(Thread.isMainThread)
await test()
assert(Thread.isMainThread)

```

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [August 2, 2024, 4:51pm UTC](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627/40 "2024-08-02T16:51:59Z")

</div>

> [@dima\_kozhinov](#):
>
> As I already said, any single thread is sequential. Suspending a function in a single thread means suspending the thread.

Means suspending the function, not thread. Thread can run other work (as @Max_Desiatov made an example of single-threaded environment). If you suspend the thread, then this thread cannot perform other tasks, which is _not_ the case.

> [@dima\_kozhinov](#):
>
> Yes. On a _different_ thread, created or reused from a pool specifically for the called `async` function. A caller thread is awaiting, that is blocked or suspended or whatever - it does not execute until the `async` function is finished.

Exactly – reused from the pool. Caller thread can be reused from the pool after function execution has been suspended.

When you call `DispatchQueue.global().async` from main thread, you do not block main thread unless work is done, main thread becomes available almost immediately. `await` work in exactly same way as @Jumhyn has illustrated few posts ago.

[Previous page](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627.md?page=1)

[Next page](https://forums.swift.org/t/can-someone-recommend-a-good-modern-tutorial-on-concurrency/73627.md?page=3)
