Задача по GCD, barrier?

swift

#1

Подскажите плз, почему в public var elements если написать async, то вернёт пустой массив?

class SafeArray<Element> {
    private var array:[Element] = []
    private let queue = DispatchQueue(label: "DispatchBarrier", attributes: .concurrent)
    
    public func append(element: Element) {
        queue.async(flags: .barrier) {
            self.array.append(element)
        }
    }
    
    public var elements: [Element] {
        var result = [Element]()
        queue.sync {
            result = self.array
        }
        
        return result
    }
 }

var safeArray = SafeArray<Int>()

DispatchQueue.concurrentPerform(iterations: 20) { (index) in
    safeArray.append(element: index)
}

print(safeArray.elements)

#2

Ну вроде все просто. Выполняться код будет следующим образом:
пошагого:

1 var result = [Element]()
2       queue.async {
3            result = self.array
4        }
5      return result
  1. создается пустой массив (спойлер, он и вернется).
  2. запускаем асинхронное получение массива (но присваивание еще не произошло)
  3. возвращаем наш пустой массив
  4. Eсли у функции будет время, она там поскрипит в потоке и присвоит результату массив (это строка. Но никуда его уже не вернет.

Собственно поэтому.

Вот поэтому для барьеров и используют синхронные очереди, чтобы точно все задачи были выполнены в нужном порядке.


#3

Всё теперь понял, спасибо)

Можешь объяснить ещё один нюанс, который я не понял)
Почему тогда возвращает весь массив, не может ли случится так, что queue.sync, встанет в очередь между какими то элементами и заблокирует очередь?
Получается queue.sync вставляется в конец очереди, после выполнения всех async задач?


#4

если в главном потоке вызовешь сихнронное выполнение то может возникнуть дедлок. Но если ты создал свою очередь, то синхронно, асинхронно можешь ее колбасить, она там по разным потокам задачи раскидывает, но я так понимаю, ты курс смотришь по потокам. Там есть как раз пример со схемой где задачи в разных потоках, но нигде не пересекаются.

Попробуй в плейграунде с этим повозиться. Я когда понял как это работает - куча вопросов по многопоточности отпало. :slight_smile:

Как sync под капотом работает я не знаю. Но не совсем так. У тебя код выполняется последовательно, просто тот код который в блоках лежит, он требует больше ресурсов усилий и он выполняется чуть позже. Если очереди асинхронные, то туда задачи запихиваются в очередь и выполняются по мере сил. Если очередь синхронная, то они в эту же очередь запихиваются, только параллельно выполнятся там не могут, хотя могут выполнятся в разных потоках.

Простой пример сделай когда будет несколько сложенных async потоков. Или sync (только надо не допускать локов) и принты везде напиши и посмотри что в консоль выведется.


#5

Ясно, попробую в playground-e)
Я понял когда мы пишем async, мы не ждём ответа и идём дальше, но тут мы доходим до sync, где он блокирует нашу очередь, следовательно когда задача queue.async c флагом barrier закончит выполняться, то начнёт задача queue.sync, а потом опять queue.async. Это как я понял)
Но в этом примере queue.sync выполняется после всех queue.async, а по чему я не понял)


#6

Я кажется понял, мы ставим в очередь, а выполнение происходит позже, а так как async c флагом barrier, то sync выполнится после их всех.


#7

Тут короче надо кучу примеров перебрать с выполнением разных задач. Тогда будет четкое понимание. Но и текущего уровня достаточно чтобы собеседование пройти в теме барьеров при асинхронном программировании. %)))

Вот поэтому тут курсы крутые :slight_smile:


#8

Да курсы крутые если их не тупо смотреть, а пытаться понять каждую строчку)
Еще раз спасибо)