Passing large amounts of data between actors without making copies

As has been illustrated here, only non-reentrant methods support transactionality (e.g., ACID’s atomicity and isolation). Swift does not support transactional async methods. If the transactions are strictly ordered, as in a serialized database, then call order must be preserved, which is also not directly supported by Swift actors.

I have not seen any proposals for adding a @nonReentrant option to methods (and possibly types) to create something similar to protected sections in Swift code. It might be useful for some of the cases described in this thread. I remember the concept was mentioned at some point very early on when reentrancy was being discussed.

Going further, something like @callOrdered or @serialized could be supported for actors to enforce strict ordering of calls, essentially creating single-threaded actors, as in Erlang.

@serialized would turn an actor into a bottleneck. Using an explicit queue (as I do in my own code) would probably be preferable in many cases. Queues tend to vary greatly in their requirements and tradeoffs, so library support may be preferable for serializing entire or partial actors.

These options would probably have a significant impact on the implementation of the runtime and would subtly change behavior.

Added:

The problem with ensuring atomicity and isolation with @nonReentrant is that it only works when one method is involved. This would not fix the common example of a bank account, for example, which is usually shown with one method. A real bank account actor would have multiple methods, e.g., deposit(), charge(), transfer(). These methods would need to be serialized and non-reentrant. A better solution would be to protect groups of methods within an actor. In C++ code, for example, this could be accomplished with protected sections across multiple methods.

Is there any interest in discussing transactional actors? If so, we could start a new thread.

1 Like