Swift Threading с DispatchGroup - PullRequest
       11

Swift Threading с DispatchGroup

0 голосов
/ 06 февраля 2019

У меня есть следующий код, который использует DispatchGroup для получения уведомлений, когда задачи выполняются следующим образом:

func getSomething(completion: ()->()) {
    completion()
}

func doSomeWork(completion: ()->()) {
    let myGroup: DispatchGroup = DispatchGroup()
    for _ in 0..<10 {
        myGroup.enter()
        getSomething {
            myGroup.leave()
        }
    }
    myGroup.notify(queue: DispatchQueue.main) { // this here is the key
        completion()
    }
}

DispatchQueue.global().async {
    print("We are doing background work")
    doSomeWork {
        print("We are done with the work - but on main thread now!!!")
    }
}

Итак, у меня есть проблема в том, что я вызываю некоторую функцию в потоке,эта функция имеет завершение, которое вызывается в некоторой фиксированной очереди.

Мои параметры:

  1. Обнаружение Thread.isMainThread и уведомление в основной или фоновой очереди
  2. Пройдите очередь, над которой мы работаем, для всех вызовов функций. Проблема: на самом деле это не шаблон интеллектуального проектирования
  3. Примите во внимание тот факт, что это завершение имеет фиксированную очередь, а затем снова отправьте вручную

Но я не доволен ни одним из вариантов ... Я бы предпочел не иметь так много отправлений.

Представьте себе:

DispatchQueue.global().async {
    print("We are doing background work")
    doSomeWork {
        DispatchQueue.global().async {
            print("Now we are in background again")
        }
    }
}

Это уже уровень-3 закрытие и не очень приятно работать, особенно если в этом фоновом асинхронном вызове у нас есть другое закрытие или уровень.

Любая помощь в том, что делать здесь, будет великолепной!Спасибо

1 Ответ

0 голосов
/ 06 февраля 2019

Проблема в том, что я вызываю функцию bla ({// block code}) в фоновой очереди.Однако bla () вызывает обработчик завершения в главном потоке из-за групп рассылки - Janosch Hübner

снова проверьте ваш фрагмент

func doSomeWork(completion: ()->()) {
    let myGroup: DispatchGroup = DispatchGroup()
    for _ in 0..<10 {
        myGroup.enter()
        getSomething {
            myGroup.leave()
        }
    }
    myGroup.notify(queue: DispatchQueue.main) { // this here is the key
        completion()
    }
}

и увидите, что, поскольку getSomethingсинхронно, вы можете просто написать

func doSomeWork(completion: ()->()) {
    //let myGroup: DispatchGroup = DispatchGroup()
    for _ in 0..<10 {
        //myGroup.enter()
        getSomething {
            //myGroup.leave()
        }
    }
    //myGroup.notify(queue: DispatchQueue.main) { // this here is the key
        completion()
    //}
}

В случае, если getSomething должен быть асинхронным, используйте соответствующий API для запуска его в некоторой группе

func doSomeWork(completion: ()->()) {
    let myGroup: DispatchGroup = DispatchGroup()
    let queue = DispatchQueue.global()
    for _ in 0..<10 {
        //myGroup.enter()
        queue.async(group: myGroup) {
            getSomething {
            //myGroup.leave()
            }
        }
    }
    myGroup.notify(queue: DispatchQueue.main) { // this here is the key
        completion()
    }
}

Запуск completion() в той же группенить (лучше сказать в той же очереди), что и doSomeWork(completion: ()->()), проста.

func doSomeWork(completion: ()->()) {
    let myGroup: DispatchGroup = DispatchGroup()
    let queue = DispatchQueue.global()
    for _ in 0..<10 {
        //myGroup.enter()
        queue.async(group: myGroup) {
            getSomething {
            //myGroup.leave()
            }
        }
    }
    //myGroup.notify(queue: DispatchQueue.main) { // this here is the key
        myGroup.wait()
        completion()
    //}
}

проверьте следующую страницу игровой площадки и посмотрите, как DispatchQueue.concurrentPerform может изменить ваш дизайн и как работает уведомление от goup

import PlaygroundSupport
import Dispatch

PlaygroundPage.current.needsIndefiniteExecution = true

let q0 = DispatchQueue.global()
let q1 = DispatchQueue(label: "my_queue", attributes: .concurrent)
let g = DispatchGroup()
let g1 = DispatchGroup()
q0.async(group: g) {
    print("1    message from \(q0): will do some concurrent jobs in the background")
    DispatchQueue.concurrentPerform(iterations: 5, execute: { (i) in
        sleep(1)
        print("\t",i)
    })
    print("2    message from \(q0): all concurrent jobs done")
    q0.async(group: g) {
        print("3    some other long time running on group...")
        sleep(3)
        print("3 ex")
    }
    q0.async(group: g1) {
        print("?    some other long time running on gifferent group...")
        sleep(4)
        print("? ex")
    }
    g1.notify(queue: .main, execute: {
        print("g1 empty")
    })
}
print("4    continue on main")
g.notify(queue: q1) {
    print("5    message from \(q1): finished a")
    DispatchQueue.main.async {
        sleep(1)
        print("6    from main, should stop playground execution?")
        //PlaygroundPage.current.finishExecution()
    }
    print("7    message from \(q1): finished b")

}
g1.notify(queue: .main) {
    print("8    from main, g1 is empty.")

}
print(" ... continue")

который печатает в моем окружении

1    message from <OS_dispatch_queue_global: com.apple.root.default-qos>: will do some concurrent jobs in the background
4    continue on main
 ... continue
8    from main, g1 is empty.
     0
     2
     1
     3
     4
2    message from <OS_dispatch_queue_global: com.apple.root.default-qos>: all concurrent jobs done
3    some other long time running on group...
?    some other long time running on gifferent group...
3 ex
5    message from <OS_dispatch_queue_concurrent: my_queue>: finished a
7    message from <OS_dispatch_queue_concurrent: my_queue>: finished b
6    from main, should stop playground execution?
? ex
g1 empty
...