Каковы преимущества и недостатки барьерных задач (Dispatch barrier) в GCD?

Ответ

Барьерные задачи (Dispatch barrier) в GCD обеспечивают синхронизацию доступа к общему ресурсу в concurrent очередях.

Преимущества:

  • Синхронизация записи при параллельном чтении: Гарантирует, что задача записи выполнится только после завершения всех ранее поставленных задач, а новые задачи начнут выполняться только после барьерной.
  • Избегание гонок данных: Полезен для операций модификации shared ресурсов (например, массива или словаря).
  • Эффективность: Позволяет сохранить параллельное выполнение задач чтения, блокируя только на время записи.

Недостатки и ограничения:

  • Только для custom concurrent очередей: Не работает с глобальными очередями (DispatchQueue.global()) или serial очередями.
  • Риск взаимоблокировок (deadlock): При неправильном вложенном использовании (например, sync-барьер в той же очереди).
  • Избыточность для простых случаев: Для исключительного доступа к ресурсу проще использовать serial очередь.

Пример использования в Swift:

let concurrentQueue = DispatchQueue(label: "com.example.queue", attributes: .concurrent)
var sharedArray = [String]()

// Параллельные операции чтения
for i in 0..<5 {
    concurrentQueue.async {
        print("Чтение: (sharedArray)")
    }
}

// Барьерная операция записи (выполнится одна, после всех чтений)
concurrentQueue.async(flags: .barrier) {
    sharedArray.append("New Item")
    print("Запись завершена")
}

// Последующие задачи (начнутся только после барьера)
concurrentQueue.async {
    print("После барьера: (sharedArray)")
}

Ответ 18+ 🔞

А, слушай, вот эта штука с барьерными задачами в GCD — это ж, блядь, как такой хитрый замок на толкучке! Представь: у тебя куча народу параллельно тащит из твоего общего ящика хуйню (читает), а ты такой: «А щас я, сука, приду и своё положу (запишу)». И чтобы никто в этот момент не сунул свои кривые ручонки, ты ставишь здорового верзилу-барьера.

В чём прикол, на самом деле:

  • Читай, не хочу, но писать — по одному: Пока этот верзила не выполнит свою работу, все, кто хотел что-то прочитать — читают себе спокойно. А вот новые желающие подождут, пока он закончит своё чёрное дело. Идеально, чтобы не было этой ебаной гонки данных, когда два потока одновременно лезут в один словарь и получается пиздец и каша.
  • Эффективность, мать её: Не надо всю очередь превращать в serial и делать всё по очереди, как последние лузеры. Чтение — пожалуйста, параллельно. А вот запись — разок подождали, зато всё чисто.

Но и подводные ебли, куда ж без них:

  • Только свои, блядь, очереди: Эту фишку нельзя впендюрить в глобальные системные очереди (DispatchQueue.global()). Только в свои собственные, которые ты создал с флагом .concurrent. В serial очередях это вообще бессмысленно, там и так всё по одному.
  • Мёртвая хватка (deadlock): Если ты внутри барьерной задачи, которая выполняется асинхронно (async), вдруг решишь синхронно (sync) вызвать ещё что-то на ЭТОЙ ЖЕ очереди — всё, пизда, зависнешь навечно. Сам себя ждёшь, дурачок.
  • Из пушки по воробьям: Если у тебя ресурс настолько хрупкий, что к нему вообще всегда только по одному можно подходить, то проще сразу использовать serial очередь и не париться с барьерами.

Ну и как это выглядит в коде, смотри:

// Создаём свою concurrent очередь, а не системную!
let concurrentQueue = DispatchQueue(label: "com.example.queue", attributes: .concurrent)
var sharedArray = [String]() // Наш общий ресурс, который все хотят

// Параллельные операции чтения — все лезут сразу, как тараканы
for i in 0..<5 {
    concurrentQueue.async {
        print("Чтение: (sharedArray)")
    }
}

// А вот тут — БАРЬЕР, сука! Все встали. Запись будет только ОДНА.
concurrentQueue.async(flags: .barrier) {
    sharedArray.append("New Item") // Модифицируем ресурс в гордом одиночестве
    print("Запись завершена")
}

// И только после того, как барьерная задача отъебалась,
// эти задачи снова побегут параллельно
concurrentQueue.async {
    print("После барьера: (sharedArray)")
}

Короче, штука мощная, но, как и всё в многопоточности, требует, чтобы башка думала. А то так и до взаимоблокировок недалеко, ёпта.