Why are we allowed to mutate actor-isolated properties from escaping closures?

why is this allowed to compile? it seems like self.index ought to be gated with await….

actor Foo 
{
    var index:Int 
    ...

    func bar() 
    {
            Task 
            {
                let index:Int = self.index 
                self.index += 1
                return File.load(index)
            }
    }
}

Task.init(_:)'s closure is marked @_inheritActorContext, which means it executes isolated to the enclosing actor. https://github.com/apple/swift/blob/main/stdlib/public/Concurrency/Task.swift#L445

  public init(
    priority: TaskPriority? = nil,
    @_inheritActorContext @_implicitSelfCapture operation: __owned @Sendable @escaping () async -> Success
  ) {
3 Likes

so this would effectively serialize all of the file loading operations in this example? do i need detached(priority:operation:) to make it truly parallel?

Currently that's right yeah.

Doing any FileIO on any of the swift concurrency pools is a recipe for pain though, you might cause starvation to the entire (swift concurrency) runtime. If it's actual file IO today you still might prefer kicking it off to its own thread pool / dispatch queue.

That's one of the topics custom executors would address, i.e. passing an explicit executor to a task.

2 Likes

for things that aren’t disk-oriented, is there a way to opt-out of @_inheritActorContext without detatching the task, since that would no longer respond to cancellation of the parent task?

Task{} doesn’t either since it’s an unstructured task.

It’s not a child task, it has no parent, thus, does not participate in any cancellation dance with the parent. You’d have to do a wirhCanxellationHandler around the spawning of that task, and cancel it’s handle if you wanted that.

—-
Having that said, perhaps if this becomes a common case we could build some sugar for it eventually

2 Likes

wait, so what stops the Tasks when i quit the main application?

What do you mean "quit main application"? Kill the process/app?
Tasks are just objects in memory really, they happen to run on some threads, process goes away, they go away too. Nothing to do with cancellation really.

Cancellation is only cooperative, you may want to read the https://github.com/apple/swift-evolution/blob/main/proposals/0304-structured-concurrency.md#cancellation section on cancellation if not sure how it works. I.e. cancelling tasks does not "stop" them.

4 Likes
Terms of Service

Privacy Policy

Cookie Policy