Prevent thread switches if no suspension happens in the call stack

115 views Asked by At

In a call chain of async methods, where none of the functions in the call stack suspend, how can we instruct the runtime not to do a thread switch?

Given the code below:

import SwiftUI

@main
struct MyApp: App {
    @StateObject var appCoordinator = AppCoordinator()

    var body: some Scene {
        WindowGroup {
            EmptyView()
                .task {
                    await appCoordinator.start(settings: UserDefaults.standard)
                }
        }
    }
}

@MainActor
final class AppCoordinator: ObservableObject {
    func start(settings: Settings) async {
        try? await settings.write(bool: false, atKey: "isFirstRun")
    }
}

protocol Settings {
    func write(bool: Bool, atKey key: String) async throws
}

extension UserDefaults: Settings {
    func write(bool: Bool, atKey key: String) async throws {
        set(bool, forKey: key)
    }
}

, the following happen:

  • the .task body calls the appCoordinator.start() function from the main thread (since the task inherits the current actor context)
  • appCoordinator calls settings.write from the main thread (as AppCoordinator is @MainActor)
  • however once the execution reaches the body of the write(bool:atKey:) function, the execution is moved to another thread.

I know that we should not make assumptions about on which thread the async functions execute, however for cases like this, the thread switch affects performance, and IMO is not needed. Even if an actor would've implement the protocol, its executor would've been the one that would ensure the atomicity of the actor's operations.

I could decorate the write(bool:atKey:) function with @MainActor, however that doesn't sound right.

I could also drop the async requirement over the protocol, however in the actual project, the UserDefults instance is injected via a protocol that needs to declare async throw functions.

Bottom line, given a call chain if async methods, where none of the functions suspend, is there a way to prevent the thread switches?

0

There are 0 answers