Сделайте общий кэш потокобезопасным через параллельную очередь и барьерную запись
Сделайте этот кэш «ключ-значение» потокобезопасным. Параллельные чтения должны идти одновременно, но запись должна быть эксклюзивной — ни чтение, ни другая запись не перекрывают её.
Ограничения:
- Используйте одну приватную параллельную
DispatchQueue. - Чтения идут параллельно; записи используют барьер.
- Не сериализуйте чтения между собой.
final class Cache {
private var storage: [String: Data] = [:]
func value(for key: String) -> Data? {
// ваш код здесь
}
func set(_ value: Data, for key: String) {
// ваш код здесь
}
}
Допишите реализацию.
Возьмите приватную параллельную DispatchQueue. Чтения через queue.sync идут параллельно; записи — через queue.async(flags: .barrier), одни. Обычный sync даёт записи перекрыться с чтениями — эксклюзивной её делает .barrier.
- ✗Думают, что обычное чтение
syncделает параллельные записи эксклюзивными - ✗Ставят
.barrierна чтения, бессмысленно их сериализуя - ✗Считают, что один FIFO-порядок делает параллельный доступ безопасным
- →Почему чтения должны использовать
sync, а неasync, чтобы вернуть значение? - →Что происходит с чтениями, поставленными после барьерной записи?
Приватная параллельная очередь: чтения через sync идут параллельно, запись через async(flags: .barrier) выполняется эксклюзивно.
final class Cache {
private var storage: [String: Data] = [:]
private let queue = DispatchQueue(label: "cache", attributes: .concurrent)
func value(for key: String) -> Data? {
queue.sync { storage[key] } // параллельные чтения
}
func set(_ value: Data, for key: String) {
queue.async(flags: .barrier) { // эксклюзивная запись
self.storage[key] = value
}
}
}
Без .barrier запись async на параллельной очереди перекрылась бы с идущими чтениями — гонка данных. Барьер ждёт завершения текущих чтений, выполняется один и лишь потом пускает новые чтения.