DispatchGroup 中的几个任务。他们会 运行 有序吗?

Several tasks inside a DispatchGroup. Will they run in order?

在下面的代码中,附加到数组是否安全?订单保证能维持吗?

let processedData: [SomeType] = []
let dispatchGroup = DispatchGroup()
for _ in 0..<N {
    dispatchGroup.enter()
    startSomeAsyncTaskXYZ { (data, error) in
        // handle error and process data
        // add processed data to an array
        processedData.append(..)
        dispatchGroup.leave()
    }
}
dispatchGroup.notify(queue: .main) {
    // update UI
}

DispatchGroup 与执行顺序无关。它只是一种跟踪任务组完成情况的方法。

小组的组成任务是运行async还是sync,以及顺序如何,完全取决于您如何使用DispatchQueues。

要坚持 DispatchGroup 同时保留所需的异步性质和预期的顺序,请将您的数组设为可选数组,并按照任务完成的顺序填充它:

var processedData: [SomeType?] = Array(repeating: nil, count: N)
let dispatchGroup = DispatchGroup()
for idx in 0..<N {
    dispatchGroup.enter()
    startSomeAsyncTaskXYZ { (data, error) in
        // Ensure we always .leave() after we're done
        // handling the completion of the task
        defer { dispatchGroup.leave() }

        guard let data = data,
              error == nil else {
            // TODO: Actual error handling
            return
        }

        // This needs to be .sync now (not .async) to ensure
        // the deferred dispatchGroup.leave() is not called
        // until *after* we've updated the array
        DispatchQueue.main.sync {
            processedData[idx] = SomeType(data: data)
        }
    }
}
dispatchGroup.notify(queue: .main) {
    // update UI
}

刚刚用我的应用程序完成了这个。我有一些需要按顺序完成的异步任务。实现这一目标的最佳方法是通过 dispatchGroup()semaphore().

基本思想是 dispatchGroup 不按特定顺序获取数据,但 semaphore 在需要时按特定顺序获取数据。

这是一个很好的演示视频:https://www.youtube.com/watch?v=6rJN_ECd1XM&ab_channel=LetsBuildThatApp

一些示例代码如下所示:

let dispatchQueue = DispatchQueue.global(qos: .userInitiated)
let dispatchGroup = DispatchGroup()
let semaphore = DispatchSemaphore(value: 0)

override func viewDidLoad() {
dispatchQueue.async {
        
        // --------------
        // Family members
        // --------------
        
        // Get members and household information first (esp. payday time and time zone), then everything else
        self.dispatchGroup.enter()
        MPUser.loadFamilyMembers {
            
            print("We got us some fambly members!")
            
            self.dispatchGroup.leave()
            self.semaphore.signal()
        }
        
        // ^^^ Wait for above code to finish ('signal') before moving on (in other words, get users first)
        self.semaphore.wait()

        // --------------
        // Household info
        // --------------

        self.dispatchGroup.enter()
        FamilyData.observeHouseholdInformation {
            self.dispatchGroup.leave()
            self.semaphore.signal()
        }

        // ^^^ Wait for above code to finish ('signal') before moving on (in other words, get users first, then household info)
        self.semaphore.wait()

        // ---------------
        // Everything else
        // ---------------

        self.dispatchGroup.enter()
        Setup.observeProgress {
            self.dispatchGroup.leave()
        }
        
        self.dispatchGroup.enter()
        OutsideIncome.observeUserOutsideIncomeBudget {
            self.dispatchGroup.leave()
        }
        
        self.dispatchGroup.enter()
        MPUser.observeCurrentEarnings {
            self.dispatchGroup.leave()
        }
        
        self.dispatchGroup.notify(queue: .main) {
            
            let end = Date()
            print("\nAll functions completed in \(end.timeIntervalSince(self.start!).rounded(toPlaces: 2)) seconds!\n")
            self.sendUserToCorrectPage()
        }
    }
}