Nope, you're right. Even that worst-case-scenario (long running actor method with no suspension points) would be no worse than a serial dispatch queue. In fact, it'd be potentially much better, since it's mandatory to be async so callers are not blocked. And realistically in a lot of cases the long running part would be offloaded to an async function, or at least broken down at some points, where other calls would take over. It might even be possible to prioritise high QoS calls when the current executing task suspends, something that's impossible with a serial queue. So there are actually many ways in which the actor model is better. Thinking about it, it's a very clever solution.
My only concern (what motivated my previous post) is that it could be more error prone. It seems to me that's it's easier to mistakenly write this:
Swift:
actor FooActor {
var fooState: Int = 0
func fooMethod() {
longRunningThing()
fooState += 1
}
}
And forget that the method is going to run serially and block all other calls to the actor during its execution, than to mistakenly do this:
Swift:
let dispatchQueueForIO = DispatchQueue(label: "Serial Queue for I/O")
dispatchQueueForIO.async {
longRunningThing()
fooSeriallyAccessedOnlyProperty += 1
}
And forget that it's running on the serial queue. Ideally, both cases should move the
longRunningThing()
outside the method/async block. But in the latter is extremely clear that the context is a serial queue, so the error is more evident. More verbose, in a way. That may be because I'm less used to working with actors, admittedly.