简体   繁体   English

Swift 3 DispatchGroup单成功DispatchWorkItem

[英]Swift 3 DispatchGroup single success DispatchWorkItem

Here is the deal. 这是交易。 I'm attempting to walk the tree. 我试图在树上走。 But want to do so concurrently. 但是要同时进行。 So each time i walk onto a node i need to concurrently walk all of it's nodes and so on. 因此,每次我走到一个节点上时,我都需要同时走动它的所有节点,依此类推。 But. 但。 I do not want to wait for the whole DispatchGroup to finish to get results since it's like a worst case scenario in Big O. Instead i want to cancel all the other DispatchWorkItems and leave group for them in the successing one. 我不想等待整个DispatchGroup完成以获取结果,因为在Big O中这是最坏的情况。相反,我想取消所有其他DispatchWorkItems并在后续的工作组中保留它们。 Tried to do so with counting the task which ended. 试图通过计算结束的任务来做到这一点。 Obviously i'm doing something wrong or misunderstand how to use this. 显然我在做错事或误解了如何使用它。 The code below was written just for purpose of example and to test the idea. 下面的代码仅用于示例目的和测试想法。 Consider the real world situation is that in the DispatchWorkItem you can call recursively another handle function of a current node of tree. 考虑到现实情况,您可以在DispatchWorkItem中递归调用树的当前节点的另一个handle函数。

func handle(completion: @escaping (Int) -> Void) {
    var result: Int = 0


    var count = 7
    let group = DispatchGroup()
    let queue = DispatchQueue(label: "q", attributes: .concurrent)

    var items = [DispatchWorkItem]()

    let item1 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...1000 { continue }
        count -= 1
        group.leave()
        print("left 1")
    }
    let item2 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...2000 { continue }
        count -= 1
        group.leave()
        print("left 2")
    }
    let item3 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...6000 { continue }
        count -= 1
        group.leave()
        print("left 3")
    }
    let item4 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...3000 { continue }
        result = 42

        items.forEach { $0.cancel() }

        for _ in 0..<count {
            group.leave()
        }

        print("ok; left 4")
    }
    let item5 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...50000 { continue }
        count -= 1

        group.leave()
        print("left 5")
    }
    let item6 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...6000 { continue }
        count -= 1
        group.leave()
        print("left 6")
    }
    let item7 = DispatchWorkItem(flags: .inheritQoS) {
        for _ in 0...8000 { continue }
        count -= 1
        group.leave()
        print("left 7")
    }

    items.append(item1)
    items.append(item2)
    items.append(item3)
    items.append(item4)
    items.append(item5)
    items.append(item6)
    items.append(item7)

    for item in items {
        group.enter()
        queue.async(execute: item)
    }

    group.notify(queue: queue) { 
        return
    }
}

test() {
    handle { result in
        print(result)
    }

}

You can't be reading from and writing to your count variable from multiple threads at once. 您不能一次从多个线程读取和写入计数变量。 You need to put a mutex lock on the count. 您需要对互斥锁进行计数。 You have an unstable situation trying to access and/or change count from multiple threads. 您遇到不稳定的情况,试图从多个线程访问和/或更改计数。 Also, you should design this to not need counting at all. 另外,您应该设计为根本不需要计数。

A couple of thoughts: 一些想法:

  1. If you want to cancel a time consuming task, you need to periodically check isCancelled . 如果要取消耗时的任务,则需要定期检查isCancelled See https://stackoverflow.com/a/38372384/1271826 . 参见https://stackoverflow.com/a/38372384/1271826

  2. If you are going to update count or items from multiple threads, you have to synchronize that interaction (eg with a lock or dedicated serial queue). 如果要更新多个线程中的countitems ,则必须同步该交互(例如,使用锁或专用串行队列)。 Int and Array are not thread-safe, so you'll have to manage that yourself. IntArray不是线程安全的,因此您必须自己进行管理。

  3. Keeping track of count and using DispatchGroup and keeping track of your own collection of DispatchWorkItem references is going to take a little work. 跟踪count并使用DispatchGroup并跟踪您自己的DispatchWorkItem引用集合将需要一些工作。 Operation queues get your out of all of that. 操作队列使您摆脱了所有这些。 That having been said, if maximum efficiency is required, then perhaps you want to stay within dispatch queues, but it's just a lot more work. 话虽这么说,如果需要最大的效率,那么也许您想留在调度队列中,但这只是很多工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM