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 whenordering: .strict
, or directly when we are already on queue, andordering: .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