gpt4 book ai didi

swift - DispatchGroup 通知 block 被提前调用

转载 作者:可可西里 更新时间:2023-11-01 01:07:35 30 4
gpt4 key购买 nike

在我的应用程序中早期调用 DispatchGroup 的通知 block 时出现问题,并制作了这个 playground 示例进行实验。根据输出,有时它甚至在第一个 .leave() 之前被调用。感觉我错过了一些明显的东西,现在我已经看了太久了。

let s = DispatchSemaphore(value: 1)
let dg = DispatchGroup()
func go() -> Void {
for i in 1...2 {
doWork(attemptNo: i, who: "Lily", secs: Double.random(in: 1.0...5.0))
doWork(attemptNo: i, who: "Emmie", secs: Double.random(in: 1.0...10.0))
doWork(attemptNo: i, who: "Wiley", secs: Double.random(in: 1.0...3.0))
}
}
func doWork(attemptNo: Int, who: String, secs: TimeInterval) -> Void {
DispatchQueue.global().async {
dg.enter()
print("\(who) wants to work, will wait \(secs) seconds, attempt #\(attemptNo)")
if s.wait(timeout: .now() + secs) == .timedOut {
print("\(who) was denied. No soup for me! Task #\(attemptNo) not going to happen.")
dg.leave()
return
}
let workSecs = UInt32(Int.random(in: 1...3))
print("\(who) went to work for \(workSecs) seconds on task #\(attemptNo)")

DispatchQueue.global().asyncAfter(deadline: .now() + TimeInterval(workSecs)) {
print("\(who) is sliding down the dinosaur tail. Task #\(attemptNo) all done!")
s.signal()
dg.leave()
}
}
}
go()
dg.notify(queue: .global(), execute: {print("Everyone is done.")})

示例输出:

Emmie wants to work, will wait 4.674405654828654 seconds, attempt #1
Lily wants to work, will wait 1.5898288206500877 seconds, attempt #1
Wiley wants to work, will wait 1.2182416407288 seconds, attempt #1
Lily wants to work, will wait 3.3225083978280647 seconds, attempt #2
Everyone is done.
Wiley wants to work, will wait 2.801577828588925 seconds, attempt #2
Emmie wants to work, will wait 8.9696422949966 seconds, attempt #2
Lily went to work for 3 seconds on task #2
Wiley was denied. No soup for me! Task #1 not going to happen.
Lily was denied. No soup for me! Task #1 not going to happen.
Wiley was denied. No soup for me! Task #2 not going to happen.
Lily is sliding down the dinosaur tail. Task #2 all done!
Emmie went to work for 3 seconds on task #1
Emmie is sliding down the dinosaur tail. Task #1 all done!
Emmie went to work for 2 seconds on task #2
Emmie is sliding down the dinosaur tail. Task #2 all done!

在这种情况下,“每个人都完成了”几乎是立即发生的,因为 .leave 伴随着没有得到信号量或在“工作”完成之后,这没有意义。请帮忙。

最佳答案

您的主要问题是您在错误的地方调用了 dg.enter()。您总是希望在异步调用之前调用 enter(),并希望在异步调用完成时调用 leave()

在编写代码时,for 循环在第一次调用 enter 之前完成,这就是触发 notify 的原因立即。

func doWork(attemptNo: Int, who: String, secs: TimeInterval) -> Void {
dg.enter()
DispatchQueue.global().async {
print("\(who) wants to work, will wait \(secs) seconds, attempt #\(attemptNo)")
if s.wait(timeout: .now() + secs) == .timedOut {
print("\(who) was denied. No soup for me! Task #\(attemptNo) not going to happen.")
dg.leave()
return
}
let workSecs = UInt32(Int.random(in: 1...3))
print("\(who) went to work for \(workSecs) seconds on task #\(attemptNo)")
sleep(workSecs)
print("\(who) is sliding down the dinosaur tail. Task #\(attemptNo) all done!")
s.signal()
dg.leave()
}
}

您的代码还奇怪地使用了信号量和 sleep 。我想这是模拟长时间运行的后台进程的尝试。

关于swift - DispatchGroup 通知 block 被提前调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54367351/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com