3

Imagine I'm in a class annotated with @MainActor so that all the functions are tied to the main actor. I'm trying to understand what the difference is between doing the following:

func bar() {
  Task.detached(priority: .background) {
    await foo()
  }
}

func foo() async {
  ...
}

vs

func bar() {
  Task(priority: .background) {
    await foo()
  }
}

nonisolated func foo() async {
  ...
}

Are they the same?

Rob
  • 415,655
  • 72
  • 787
  • 1,044
Tometoyou
  • 7,792
  • 12
  • 62
  • 108
  • Well, in terms of "what actor would the execution of `foo` be isolated to", it is the same in both cases, but there might be other aspects of this that I did not consider. Also note that if `foo` is `nonisolated` then it *could* be run on non-main threads, by some other code. – Sweeper Oct 27 '22 at 19:24
  • Wait, isn’t `foo` running on a non Main thread in my examples? – Tometoyou Oct 27 '22 at 23:19
  • Nope. In your first example, `foo` is isolated to the main actor because it is inside a class bearing the `@MainActor` declaration. It doesn’t matter that it was called from a detached task that is not on the main actor; the first `foo` will still run on the main actor. – Rob Oct 27 '22 at 23:42

1 Answers1

1

You said:

Imagine I'm in a class annotated with @MainActor so that all the functions are tied to the main actor. I'm trying to understand what the difference is between doing the following:

func bar() {
  Task.detached(priority: .background) {
    await foo()
  }
}

func foo() async {
  ...
}

The bar method creates a non-structured task, which, because it is a detached task, is not on the current actor. But that task will await the foo method, which will run on the main actor. The fact that foo is in a class bearing the @MainActor designation means that it is isolated to that actor, regardless of which Swift concurrency context you invoke it.

But, in this case, there is little point in launching a detached task that only awaits an actor-isolated function.

You continue:

vs

func bar() {
  Task(priority: .background) {
    await foo()
  }
}

nonisolated func foo() async {
  ...
}

In this case, bar will launch a task on the current (main) actor, but it will await the result of foo, which is nonisolated (i.e., not isolated to the main actor).

So, the difference is that the first example, foo is actor-isolated, but it is not in the second example.

Rob
  • 415,655
  • 72
  • 787
  • 1,044