大中央调度多个调度组 [英] Grand Central Dispatch Multiple DispatchGroups

查看:138
本文介绍了大中央调度多个调度组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个异步呼叫.一个返回数据,两个返回使用Firebase从S3返回的图像.我有一个后台DispatchQueue和三个调度组.我需要一种让他们同步执行的方法,但是他们不需要!我已经尝试了一切,然后.notify立即执行,这是错误的.

I have three async calls. One returns data, and two return images from S3 using firebase. I have one background DispatchQueue, and three dispatch groups. I need a way for them to execute synchronously, but they don't! I have tried everything, and .notify executes immediately, which is wrong.

的输出是:
图像已完成
一切都完成了
group.notify完成
getImages()已完成

The output of this is:
images done
all is done
group.notify is done
getImages() is done

我想了解的是为什么在group.notify完成之前执行imagesdone?我需要执行第一个组,然后执行imagesGroup,然后执行avaGroup.

What I want to understand is why is imagesdone executed before group.notify is done? I need to execute the first group, then imagesGroup, then avaGroup.

我基本上有三个异步调用,第二个/第三个可能是多个异步调用.如何等待它们完成,然后执行后续调用?

I essentially have three async calls, and the 2nd/3rd may be multiple async calls. How can I wait for them to complete, then execute subsequent calls?

func loadFriendPhotos() {

    let backgroundQueue = DispatchQueue(label: "com.app.queue",
                                        qos: .utility,
                                        target: nil)

    let group = DispatchGroup()
    let imageGroup = DispatchGroup()
    let avaGroup = DispatchGroup()
    typealias tempAlias = (username:String, imageURL: String, pathUrl:String)

    var tempAliasArray = [tempAlias]()
    var imageArray = [UIImage]()
    var avaImageArray = [UIImage]()

    group.enter()
    let workItem = DispatchWorkItem {
        databaseRef.child("friendPhotos").child(globalUsername).observeSingleEvent(of: .value, with: { (snapshot) in
            if snapshot.exists() {

                let enumerator = snapshot.children
                var childrenCount = snapshot.childrenCount


                while let rest = enumerator.nextObject() as? FIRDataSnapshot {

                    let name = rest.childSnapshot(forPath: "username").value as! String
                    let downloadURL = rest.childSnapshot(forPath: "downloadURL").value as! String
                    let uid = rest.childSnapshot(forPath: "uid").value as! String
                    let pathURL = rest.childSnapshot(forPath: "pathURL").value as! String
                    let downloadURLRef = storage.reference(forURL: downloadURL)

                    let newTempAlias = tempAlias(name, downloadURL, pathURL)
                    tempAliasArray.append(newTempAlias)
                }
                group.leave()
            }
        })
    }

    func getAvaImages() {
        for index in tempAliasArray{
            avaGroup.enter()
            let avaItem = DispatchWorkItem {
                let avaURLRef = storage.reference(forURL: index.1)
                avaURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
                    if (error == nil) {
                        print("success!")
                        let picData = UIImage(data:data!)
                        avaImageArray.append(picData!)

                    } else {
                        print(error?.localizedDescription)
                    }
                    print("we left getAvaImages()")
                    avaGroup.leave()

                }
            }
            backgroundQueue.async(execute: avaItem)
        }
    }

    func getImages() {
        for index in tempAliasArray{
            imageGroup.enter()
            let imageItem = DispatchWorkItem {
                let downloadURLRef = storage.reference(forURL: index.1)
                downloadURLRef.data(withMaxSize: 2 * 1024 * 1024) { (data,error) in
                    if (error == nil) {
                        let picData = UIImage(data:data!)
                        imageArray.append(picData!)
                    } else {
                        print(error?.localizedDescription)
                    }
                    print("we left getImages()")
                    imageGroup.leave()
                }
            }
            backgroundQueue.async(execute: imageItem)
        }
    }

    backgroundQueue.sync(execute: workItem)

    group.notify(queue: DispatchQueue.main, execute: {
        print("group.notify is done")
        getImages()
    })
    imageGroup.notify(queue: DispatchQueue.main, execute: {
        print("images done")
        getAvaImages()
    })
    avaGroup.notify(queue: DispatchQueue.main, execute: {
        print("all is done")
    })
 }

推荐答案

您正在呼叫imageGroup.notify,因为imageGroup中没有任何内容,因此它会立即发出通知.同样,avaGroup会立即通知您,因为在您调用它的那一刻它是空的.

You're calling imageGroup.notify at a point that there is nothing in imageGroup, so it immediately notifies. Similarly, avaGroup notifies immediately since it is empty at the point that you call it.

但是我不理解所有的间接和组以及三个数组.为什么在处理每个图像之前必须等待所有图像下载?为什么不只为一个元素在原始循环内开始下一步呢?像这样:

But I don't understand all the indirection and groups and three arrays. Why do you have to wait for all the images to download before you deal with each image? Why not just kick off the next step inside the original loop for just one element? Something like this:

var allTheResults = []

group.enter() // Enter once for the top-level
kickOffAsyncWithCompletion { resultList in

    for item in resultList {
        let resultThing = doSomeStuffToSetupNextLevel()

        group.enter() // Enter once per thing we iterate over

        kickOffNestedAsync(with: resultThing, completion: { result in
            let finalResult = computeFinalResult(fromResult: result)
            allTheResults.append(finalResult)
            group.leave() // leave once per thing we iterate over
        })
    }
    group.leave() // leave once for the top level
}

group.notify { doThing(withFinalResults: allTheResults) }

如果要协调一组操作的端点,则希望所有这些操作都在同一个组中使用,而不是在每个操作中分别使用不同的组.

If you want to coordinate the endpoint of set of operations, you want all those operations to be working with the same group, not separate groups per operation.

这篇关于大中央调度多个调度组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆