I was asked to implement a thread safe dictionary in swift, I used the common approach:
class MutableDictionary {
var dictionary: [String : Any] = [:]
var queue = DispatchQueue(label: "queue", attributes: .concurrent)
func object(for key: String) -> Any? {
queue.sync {
return dictionary[key]
}
}
func set(_ object: Any?, for key: String) {
queue.async(flags: .barrier) {
self.dictionary[key] = object
}
}
}
However, the following up question is:
- What's the difference with using
concurrent
+barrier
vs just using aserialQueue
for setting in this case? - I did a testing on playground, I wrapped the get and set with 1000 time for loop, it turns out that the behavior for both serial and concurrent queue is almost the same.
- Why the setting always raise an error?
- What does concurrent queue do better in this case (for both get and set) compared to a serial queue?
- In iOS, when should I choose serial queue over concurrent queue? And vice-versa?
concurrent + barrier
can run multipleread
at the same time.serial queue
can only run one task (read/write) at a time.the results are the same, or even that the
serial queue
is better because you're using only one thread to run. You can only take advantage of theconcurrent + barrier
implementation when read/write operations happen on multiple thread/queue. In this case, theserial queue
is better because you don't need to look and switch between queue/thread.Full source code, please?
Concurrent + barrier
might be better or not, as in (2), sometimes if you can ensure all operations happen in the same thread, thenserial queue
is better.It depends on your case, as mentioned in (2), (4). One more thing about
concurrent + barrier
, sometimes it isn't a good choice as you think. Imagine:You're implementing a feature that needs to do a heavy write operation, for example, you're reading your dict and calculating a new value, and updating the dict. You wrap all of these steps in a
queue.async(flags: .barrier)
block.You expect these steps are running in your thread (background thread) and it doesn't block the main queue from reading the dict to update UI. But it does block the main queue, right?
Read
operations from the main queue have to wait forbarrier
block to finish first.If your application consumes a lot of CPU, you may have to wait for OS to find the thread for your
update
steps, which means you have to spend more time on it.