如何在后台线程中使用 DispatchGroup?

Gus*_*uto 4 swift

我有两个函数(或任务),我想一个接一个地运行,我正在使用 DispatchGroup 来跟踪它们并在它们完成时通知我。现在它们正在主线程中完成,但我想在后台线程中运行这些任务。我该怎么做呢?我尝试了几种方法,但它们要么同时运行,要么在第一个方法完成后出现异常错误。以下代码依次执行任务,但如果我在函数内调用 Thread.current,我可以看到它们正在主线程中运行。

@objc func doWorkFunctions(){
    taskGroup.enter()
    DispatchQueue.global(qos: .background).sync {
        self.firstFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.enter()
    DispatchQueue.global(qos: .background).sync {
        self.secondFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.notify(queue: .main) {
        print("All tasks completed")
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我使用以下代码,它们会同时运行,但在后台线程中运行。

@objc func doWorkFunctions(){
    taskGroup.enter()
    DispatchQueue.global(qos: .background).async {
        self.firstFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.enter()
    DispatchQueue.global(qos: .background).async {
        self.secondFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.notify(queue: .main) {
        print("All tasks completed")
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直在寻找又寻找,但似乎找不到我的问题的答案或对此事的澄清。有人可以提供一些关于这里发生的事情的指导吗?这些是案例中所涉及的功能。他们模拟一项长期任务来练习跟踪进度。

func firstFunction(completion: @escaping()->Void){
    print(Thread.current)
    if childProgressOne.isCancelled { return }
    for i in 1...5 {
        sleep(1)

        childProgressOne.completedUnitCount = Int64(i * 20)

        print("Child Progress One: \(childProgressOne.fractionCompleted)")
        print("Total Progress: \(totalProgress.fractionCompleted)")
    }
    completion()
}

func secondFunction(completion: @escaping()->Void){
    print(Thread.current)

    if childProgressTwo.isCancelled { return }
    for i in 1...5 {
        sleep(1)

        childProgressTwo.completedUnitCount = Int64(i * 20)

        print("Child Progress Two: \(childProgressTwo.fractionCompleted)")
        print("Total Progress: \(totalProgress.fractionCompleted)")
    }
    completion()
}
Run Code Online (Sandbox Code Playgroud)

这也按顺序执行它们,但在函数内调用 Thread.current 告诉我它们正在主线程中执行,即使它们被调用到后台线程。

 @objc func doWorkFunctions(){
    DispatchQueue.global(qos: .background).sync {
        self.taskGroup.enter()
        self.firstFunction {
            self.taskGroup.leave()
        }
        self.taskGroup.enter()
        self.secondFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.notify(queue: .main) {
        print("All tasks completed")
    }
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*ier 6

鉴于您所描述的,我可能根本不会在这里使用调度组。我只是链接这些方法:

@objc func doWorkFunctions() {
    DispatchQueue.global(qos: .background).async {
        self.firstFunction {
            self.secondFunction {
                DispatchQueue.main.async {
                    print("All tasks completed")
                }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但假设你有充分的理由在这里建立一个组,那么你需要做的就是使用.notify它们来同步它们。.notify说“当组为空时,将此块提交到此队列。”

@objc func doWorkFunctions(){
    let queue = DispatchQueue.global(qos: .background)

    taskGroup.enter()
    queue.async {
        self.firstFunction {
            self.taskGroup.leave()
        }
    }

    taskGroup.notify(queue: queue) {
        self.taskGroup.enter()

        self.secondFunction {
            self.taskGroup.leave()
        }

        self.taskGroup.notify(queue: .main) {
            print("All tasks completed")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(这里您可能不需要taskGroup成为实例属性。您可以将其设为局部变量并且需要更少的self.引用。每个块都有对该组的引用,因此它将一直存在,直到所有块都完成为止。)