Hi guys,
My existing concurrent code uses a lot of traditional DispatchQueue patterns, from using a serial dispatch queue to protect internal state to callbacks to user specified callback queues.
I am trying to bring that code into the new Swift concurrency world, and as much as I love the experience, one thing becomes clear, at least for me. It's impossible right now (due to many isolation related shortcomings that are being worked on) to move everything to actors just not yet.
And although I use a lot of .dispatchPrecondition and other helper methods to use dispatch queues cleverly, ...
... it got me thinking. What if I create a small package that will vend several primitives, property wrappers, or macros to help using DispatchQueue based concurrency systems correctly?
The way I think about it (before writing any code):
IdentifiableDispatchQueue will represent a triple with DispatchQueue, DispatchSpecificKey, and associated DispatchSpecificValue.
Than when declaring a variable, I can annotate it with either a property wrapper, or Swift macro to make sure it is only touched on the queue, for example like this:
@OnQueue(myIdentifiableSerialQueue, ordering: .strict)
var someInternalState: String = "Hello World"
Now either the property wrapper, or the Swift macro will make sure that
- all reads will happen either directly when already on queue, or via
DispatchQueue.sync
- all writes will happen via
DispatchQueue.async call when ordering: .strict, or directly when we are already on queue, and ordering: .relaxed.
Determining whether we are on queue will be done vie DispatchQueue.getSpecific to match against the IdentifiableDispatchQueue instance that is specifed in var declaration.
Now, I do not see any drawbacks right now (apart from potential perf impact) when using the Macro or PropertyWrapper on instance variables.
I think I can come up with a clever way to provide also .sync and .async methods on IdentifiableDispatchQueue to execute piece of work directly, or via .sync, or .async call respecting work ordering in case of .async work.
What do you think? Do you face similar problems? Are there any existing swift packages doing similar? Is it a good idea?
As much as I tried to find something, I have failed...
thanks for any inputs,
Martin