我在 playground 中尝试遵循代码,但它们似乎没有按我预期的那样工作。
在我的 mac 上,两次 group_async 操作总共导致大约 5~6 秒。
- 当我将超时时间设置为 DispatchTime.now() + 10 时,“测试返回”和“完成”都会被打印出来。
- 当我将超时时间设置为 DispatchTime.now() + 1(某些值使组超时)时,除了两个 group_async 操作中的打印代码外,什么都没有打印。
我想要的是暂停组并在超时时进行一些清理,并在组成功完成后进行一些其他进一步的操作。任何建议表示赞赏。谢谢。
import Dispatch
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
let queue = DispatchQueue.global(qos: .utility)
func test() {
let group = DispatchGroup()
__dispatch_group_async(group, queue) {
var a = [String]()
for i in 1...999 {
a.append(String(i))
print("appending array a...")
}
print("a finished")
}
__dispatch_group_async(group, queue) {
var b = [String]()
for i in 1...999 {
b.append(String(i))
print("appending array b...")
}
print("b finished")
}
let result = group.wait(timeout: DispatchTime.now() + 10)
if result == .timedOut {
group.suspend()
print("timed out")
}
print("test returns")
}
queue.async {
test()
print("done")
}
最佳答案
此代码片段提出了各种不同的问题:
我注意到 playground 和您在应用程序中运行它时的行为略有不同。我怀疑这是
PlaygroundPage
和 GCD 的needsIndefiniteExecution
的一些特质。我建议在应用程序中对此进行测试。考虑到我在下面提出的要点,当我从应用程序运行它时,它按预期工作。我注意到您采用了这种模式:
__dispatch_group_async(group, queue) { ... }
我建议:
queue.async(group: group) { ... }
您正在执行
group.suspend()
。一些注意事项:一个挂起队列,而不是组。
如果您曾经调用过
suspend()
,请确保您在某处调用了相应的resume()
。另外,请记住
suspend()
会阻止 future 的 block 开始,但它不会对可能已经在运行的 block 做任何事情。如果您想停止已经在运行的 block ,您可能想要取消它们。最后,请注意您只能挂起您创建的队列和源。您不能(也不应该)暂停全局队列。
我还注意到您在调度
test()
调用的同一个队列上使用了wait
。在这种情况下,您可以摆脱它,因为它是一个并发队列,但这种模式会引发死锁。如果可以的话,我建议完全避免wait
,当然也不要在调用它的同一个队列上执行它。同样,这在这里不是问题,但它是一种模式,将来可能会给您带来麻烦。就个人而言,我可能倾向于使用
notify
而不是wait
来触发代码块在两个分派(dispatch) block 完成时运行。这消除了任何死锁风险。如果我想让一段代码在一定时间后运行(即超时过程),我可能会使用计时器来触发一些清理过程,以防这两个代码块仍在运行(可能取消它们;参见 How to stop a DispatchWorkItem in GCD? ).
关于ios - 如何在 Swift 3 中处理组等待结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39970411/