I had assumed that the easy way to ensure serialized access to methods in Swift was to use the new structured concurrency approaches, specifically the actor
type.
However, it does not seem to work as expected when the method also uses structured concurrency, i.e. contains async methods.
For example:
actor MyActor {
func doSomething(_ val: Int) async {
print("Started doing something \(val)")
try! await Task.sleep(nanoseconds: 500_000_000)
print("Finished doing something \(val)")
}
}
let actor = MyActor()
for i in 1...5 {
Task { await actor.doSomething(i) }
}
I would have expected this to serialize the code in doSomething
, producing pairs of Started N
and Finished N
. Instead, I get something like:
Started 1
Started 2
Started 3
Finished 2
Finished 1
Finished 3
Given this, it appears to be unblocking access at the first suspension point (e.g. at the Task.sleep()
).
Is there an alternative approach I should be using the achieve the desired outcome?
it seems that this is intentional to allow for reentrancy.
Well, to allow reentrancy in order to avoid deadlock.
Is there a semaphore-like primitive for use with structured concurrency?
There is not one built in. You can build one, but you have to think carefully before going down that path. Remember that this reentrancy isn’t accidental. It’s there to avoid deadlock. If you go out of your way to disable this, you end up bringing back the possibility of deadlock. And while reentrancy bugs are not fun to find, deadlock bugs are worse.
Note If you bounce on over to Swift Evolution you’ll find a general consensus that some sort of reentrancy control is required, it’s just Swift concurrency is a multi-year effort and this feature isn’t part of the initial rollout.
The best tool in your arsenal here is synchronous methods. These can access your actor’s state but, if you’re running in the actor context, you don’t need to await
them and so you don’t have to worry about reentrancy. If you post more details about what your real actor is trying to do, I may be able to offer further insight.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"