我有两个功能(或任务),我想一个接一个地运行,我正在使用DispatchGroup跟踪它们,并在完成时通知我。现在,它们已经在Main线程中完成了,但是我想在后台线程中运行这些任务。我将如何去做?我尝试了几种方法,但它们同时运行,或者在第一个方法完成后出现异常错误。下面的代码一个接一个地执行任务,但是如果我在函数内部调用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")
}
}
如果我使用以下代码,它们将同时在后台线程中运行。
@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")
}
}
我一直在搜索,但是似乎找不到解决我问题或答案的答案。有人可以提供一些有关这里发生的情况的指导。这些是有问题的功能。他们模拟了一项漫长的任务来练习跟踪进度。
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()
}
这也按顺序执行它们,但是在函数内部调用Thread.current告诉我,即使在后台线程中调用它们,它们也在Main线程中执行。
@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")
}
}
答案 0 :(得分:2)
鉴于您的描述,在这里我可能根本不会使用调度组。我只是链接方法:
@objc func doWorkFunctions() {
DispatchQueue.global(qos: .background).async {
self.firstFunction {
self.secondFunction {
DispatchQueue.main.async {
print("All tasks completed")
}
}
}
}
但是,假设您有充分的理由在这里进行分组,则需要使用.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")
}
}
}
(您可能不需要taskGroup
作为实例属性。您可以将其设为局部变量,并且需要较少的self.
引用。每个块都具有对该组的引用,因此它会一直持续到所有块都完成为止。)
答案 1 :(得分:0)
如果您要做的是在后台串行运行两个函数,那么您要做的就是依次在同一队列中的同一任务中执行它们。根本不需要花哨。
您可以将其插入操场并弄乱它:
require('dotenv').config({path: <path of .env file>});
无论是在串行队列中还是在并发队列中执行这两个功能,以及是以同步还是异步方式分派这两个功能,就将问题放在同一个队列中的同一任务而言,对于您而言都是微不足道的。但是,如果将这两个功能分成两个单独的任务(或队列),那么串行化和并发性就成为一个因素。但是,请注意,术语“并发”是相对的。通过调度队列(串行或并发)执行的所有任务都与主线程并发。但是,当我们在调度队列的上下文中谈论它们时,我们几乎总是意味着与其他任务并发。
请阅读以下内容,以更好地了解什么是确切的排队:https://stackoverflow.com/a/53582047/9086770
答案 2 :(得分:0)
此解决方案是前两个答案的组合。我使用了第二个答案中的@nard,也使用了DispatchGroup。我意识到在这种情况下,实际上并不需要DispatchGroup,但是如果需要的话,这将是解决问题的一种方法。感谢@Rob Napier和@nard的指导。
import UIKit
func workOne(completion: @escaping ()->Void){
print(Thread.current)
for i in 1...4{
sleep(1)
print(i)
}
completion()
}
func workTwo(completion: @escaping ()->Void){
print(Thread.current)
for i in 5...8{
sleep(1)
print(i)
}
completion()
}
func doWork(){
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
workOne {
dispatchGroup.leave()
}
dispatchGroup.enter()
workTwo {
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
print(Thread.current)
print("completed!")
}
}
DispatchQueue.global(qos: .default).async {
doWork()
}