Ответ
Барьерная операция в GCD — это задача в concurrent (параллельной) очереди, которая выполняется эксклюзивно. Все задачи, добавленные в очередь до барьера, выполняются параллельно. Барьерная задача запускается только после их завершения, и пока она выполняется, новые задачи не начинаются. После завершения барьера очередь возобновляет параллельное выполнение.
Обычная операция в concurrent очереди выполняется параллельно с другими задачами без каких-либо ограничений.
Ключевое отличие: Барьер обеспечивает эксклюзивный доступ для синхронизации записи в общий ресурс, обычная операция — нет.
Типичное применение: Thread-safe операции записи или модификации общего ресурса (например, словаря или массива) в concurrent очереди.
Пример:
let concurrentQueue = DispatchQueue(label: "com.example.cache", attributes: .concurrent)
var cache: [String: Data] = [:]
// Множественные параллельные чтения (обычные операции)
func read(from key: String) -> Data? {
concurrentQueue.sync { // .sync для немедленного возврата значения
return cache[key]
}
}
// Запись требует эксклюзивного доступа (барьерная операция)
func write(_ data: Data, for key: String) {
concurrentQueue.async(flags: .barrier) {
cache[key] = data
}
}
Важно: Барьеры имеют смысл только в concurrent очередях, созданных с атрибутом .concurrent. В serial (последовательных) очередях все задачи и так выполняются по одной, поэтому барьер не нужен.
Ответ 18+ 🔞
А, слушай, смотри, вот эта барьерная операция в GCD — это такая, блядь, хитрая жопа, которая в параллельной очереди работает как единственный мудак в баре, который всех разгоняет и говорит: «Сейчас я один буду пиздеть, а вы все заткнитесь».
Представь себе: у тебя есть concurrent очередь — это как толпа распиздяев, которые все одновременно лезут к одному холодильнику за пивом. Обычные операции — это они все, сука, параллельно: один берёт пиво, другой колбасу, третий хуй с горы — всё одновременно, без очереди.
А барьер — это такой здоровый чувак, который приходит и орет: «Так, все нахуй отсюда! Я сейчас свой бутерброд соберу, а вы стоять будете и смотреть!». И пока он там колбасу на хлеб кладёт, нихуя не происходит — все ждут. Как он закончил — опять начинается ад и содомия.
Короче, отличие простое:
- Обычная операция — просто одна из многих, работает параллельно со всеми.
- Барьерная операция — это, блядь, царь и бог на момент своего выполнения. Все, кто был до неё, должны доёбываться. Пока она идёт — новые задачи стоят. После неё — опять свободный полёт.
Где это надо? Да когда у тебя общий ресурс, который надо писать без пиздеца. Читать могут все сразу, а вот запись — только одна, иначе получишь race condition и всё полетит в пизду.
Вот, смотри код, тут всё понятно:
let concurrentQueue = DispatchQueue(label: "com.example.cache", attributes: .concurrent)
var cache: [String: Data] = [:]
// Чтение — обычная операция, все могут лезть одновременно
func read(from key: String) -> Data? {
concurrentQueue.sync { // .sync, чтобы сразу результат получить, а не ждать
return cache[key]
}
}
// А запись — барьерная, блядь. Всех разогнал, один записал.
func write(_ data: Data, for key: String) {
concurrentQueue.async(flags: .barrier) {
cache[key] = data
}
}
И главное, ёпта, запомни: барьеры работают только в concurrent очередях! В serial очереди и так всё по одному выполняется, там ставить барьер — это как, блядь, в пустой комнате кричать «не лезьте, я один тут!». Бессмысленно и смешно.