这是交易。我试图走树。但希望同时这样做。因此,每次我走到一个节点上时,我都需要同时遍历它的所有节点,依此类推。 但。我不想等到整个调度组完成才能得到结果,因为这就像大O中最坏的情况。 相反,我想取消所有其他调度工作项目,并在下一个中为它们离开组。试图通过计算结束的任务来做到这一点。显然我做错了什么或误解了如何使用它。 下面的代码只是为了举例和测试这个想法而编写的。 考虑现实世界的情况是,在调度工作项中,您可以递归调用树的当前节点的另一个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)
}
}
您不能同时从多个线程读取和写入计数变量。 您需要对计数设置互斥锁。 您尝试从多个线程访问和/或更改计数时遇到不稳定的情况。此外,您应该将其设计为根本不需要计数。
几个想法:
-
如果要取消耗时的任务,则需要定期检查
isCancelled
。请参阅 https://stackoverflow.com/a/38372384/1271826。 -
如果要从多个线程更新
count
或items
,则必须同步该交互(例如,使用锁或专用串行队列(。Int
和Array
不是线程安全的,因此您必须自己管理。 -
跟踪
count
并使用DispatchGroup
并跟踪您自己的DispatchWorkItem
引用集合将需要一些工作。操作队列让您摆脱所有这些。话虽如此,如果需要最大的效率,那么也许您想留在调度队列中,但这只是更多的工作。