Swift: Simple DispatchQueue не запускается и уведомляет правильно - PullRequest
0 голосов
/ 29 ноября 2018

Что я делаю не так?На детской площадке все работает как надо.Но как только я разверну его на симуляторе iOS, он вернет неправильную последовательность.

@objc func buttonTapped(){

    let group = DispatchGroup()
    let dispatchQueue = DispatchQueue.global(qos: .default)

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("? \(i)")  
        }
        group.leave()
    }

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("❌ \(i)")
        }
        group.leave()
    }

    group.notify(queue: DispatchQueue.main) {
        print("jobs done by group")
    }   
}

Вывод на консоль:

ios-Simulator playground

Я не понимаю.?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Как сказал Давид , правильно используемые группы рассылки гарантируют, что уведомление будет происходить только после того, как все задачи завершатся, чего можно достичь, вызвав leave из отправленных блоков, как он показал вам.,Или же, поскольку ваши отправленные задачи сами по себе являются синхронными, вам не нужно вручную enter и leave group, но вы можете использовать group параметр async метод:

let group = DispatchGroup()
let queue = DispatchQueue.global(qos: .default)

for i in 1...4 {
    queue.async(group: group) {
        print("? \(i)")
    }
}

for i in 1...4 {
    queue.async(group: group) {
        print("❌ \(i)")
    }
}

group.notify(queue: .main) {
    print("jobs done by group")
}

Используйте group.enter() и group.leave() при вызове некоторого асинхронного метода, но в случае этих операторов print вы можете просто использовать async(group:execute:), как показано выше.

Теперь мы решили проблему, когда блок «работы, выполненные по группам» не ожидал всех отправленных задач.Но, поскольку вы выполняете всю эту диспетчеризацию в параллельную очередь (все глобальные очереди являются параллельными очередями), у вас нет никаких гарантий, что ваши задачи будут выполнены в том порядке, который вы запрашивали.Они поставлены в очередь в строгом FIFO-режиме, но поскольку они параллельны, у вас нет никаких гарантий, когда вы нажмете соответствующие операторы print.

Если вам нужно распечатать сообщения по порядку, вам придется использовать последовательную очередь.Например, если вы создаете собственную очередь, в отсутствие атрибута .concurrent, последовательная очередь создаст следующее:

// create serial queue

let queue = DispatchQueue(label: "...")

// but not your own concurrent queue:
//
// let queue = DispatchQueue(label: "...", attributes: .concurrent)
//
// nor one of the global concurrent queues:
//
// let queue = DispatchQueue.global(qos: .default)
//

И если вы запустите приведенный выше кодс этой последовательной очередью вы увидите то, что искали:

? 1? 2? 3? 4❌ 1❌ 2❌ 3❌ 4задания, выполненные группой

Но, опять же, если вы используете последовательную очередь, group будет совершенно ненужным (вы можете просто добавить задачу «завершение» как еще одну отправленную задачу)в конце последовательной очереди).Я только показываю использование последовательных очередей как способ избежать состояния гонки при отправке восьми задач в параллельную очередь.

0 голосов
/ 29 ноября 2018

Вы также должны поместить оператор group.leave() в блок dispatchQueue.async, иначе он будет выполнен синхронно до того, как асинхронный блок завершит выполнение.

@objc func buttonTapped(){

    let group = DispatchGroup()
    let dispatchQueue = DispatchQueue.global(qos: .default)

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("? \(i)")  
            group.leave()
        }
    }

    for i in 1...4 {
        group.enter()
        dispatchQueue.async {
            print("❌ \(i)")
            group.leave()
        }
    }

    group.notify(queue: DispatchQueue.main) {
        print("jobs done by group")
    }   
}
...