提问人:LCSome 提问时间:10/9/2023 更新时间:10/9/2023 访问量:31
在任务完成之前调用的 Swift DispatchGroup 通知
Swift DispatchGroup notify called before task finish
问:
我使用信号量和 DispatchGroup 处理并发网络。它在演示中工作正常。但是在我将代码复制到项目后,它不起作用。谁能找到问题?
演示:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let queue = DispatchQueue.global(qos: .default)
let semaphore = DispatchSemaphore(value: 10)
let group = DispatchGroup()
var stop = false
queue.async {
for i in 0..<10{
semaphore.wait()
queue.async(group: group, execute: { [self] in
if(stop){
return;
}
print("beigin = \(i)")
getRequestWithCallback { Bool in
print("end = \(i)")
semaphore.signal()
} error: { Bool in
print("end = \(i)")
stop = true
semaphore.signal()
}
})
}
group.notify(queue: queue) {
print("finish")
}
}
}
func getRequestWithCallback(success:successCallBack, error:errorCallBack){
sleep(2)
success(true)
}
演示结果如下:
beigin = 8
beigin = 3
beigin = 7
beigin = 0
beigin = 4
beigin = 2
beigin = 9
beigin = 5
beigin = 6
beigin = 1
end = 8
end = 2
end = 5
end = 7
end = 3
end = 0
end = 4
end = 1
end = 6
end = 9
finish
项目:
func uploadEventTrackingFiles() {
let array_all = UserDefaults.standard.array(forKey: "eventArray") ?? Array()
let params = array_all.prefix(10)
var para = [String : Any]()
let url = "https://dc-o.api.leiniao.com/frontreport/custom"
MCNetwork.share.headers = ["Content-Type": "application/json"]
let queue = DispatchQueue.global(qos: .default)
let semaphore = DispatchSemaphore(value: 10)
let group = DispatchGroup()
var stop = false
queue.async {
for i in 0..<params.count{
semaphore.wait()
queue.async(group: group, execute: {
if(stop){
return
}
para = params[i] as! [String : Any]
MCNetwork.share.request(url: url, Method: .get,Para: para,encoding:URLEncoding.default) { obj in
print("successs=\(i)")
semaphore.signal()
}RError: { err in
stop = true
print("error=\(i)")
semaphore.signal()
}
})
}
group.notify(queue: queue) {
var array_all = UserDefaults.standard.array(forKey: "eventArray") ?? Array()
array_all.removeSubrange(0..<10)
UserDefaults.standard.setValue(array_all, forKey: "eventArray")
print("finish")
}
}
}
以及项目结果:
finish
successs=2
successs=1
successs=0
successs=3
successs=5
successs=4
successs=7
successs=6
successs=8
successs=9
我找不到解决问题的方法,导致演示代码工作正常。有没有人能找到解决这个问题的理由?
答:
1赞
HangarRash
10/9/2023
#1
您有几个问题。您的演示实际上并没有模拟您的真实代码,因为您的演示实际上并不像调用 is 那样是异步的。如果你是异步的,那么你会发现你的演示会像你的真实代码一样失败。getRequestWithCallback
MCNetwork.share.request
getRequestWithCallback
第一个问题是你的信号量没有做任何事情,所以你不妨删除所有信号量的使用。
第二个也是更重要的问题是,您不应该像在实际代码中那样用于调用异步代码。实际代码失败的原因是循环立即完成,并且所有调用在调用有机会运行之前很久就完成了。在演示中,由于不是异步的,因此对 的调用在返回之前(休眠后)不会完成。async
async
MCNetwork.share.request
getRequestWithCallback
async
getRequestWithCallback
以下是重构真实代码的一种方法:
func uploadEventTrackingFiles() {
let array_all = UserDefaults.standard.array(forKey: "eventArray") ?? Array()
let params = array_all.prefix(10)
var para = [String : Any]()
let url = "https://dc-o.api.leiniao.com/frontreport/custom"
MCNetwork.share.headers = ["Content-Type": "application/json"]
let queue = DispatchQueue.global(qos: .default)
let group = DispatchGroup()
queue.async {
for i in 0..<params.count {
para = params[i] as! [String : Any]
group.enter()
MCNetwork.share.request(url: url, Method: .get,Para: para,encoding:URLEncoding.default) { obj in
print("success=\(i)")
group.leave()
} RError: { err in
print("error=\(i)")
group.leave()
}
}
group.notify(queue: queue) {
var array_all = UserDefaults.standard.array(forKey: "eventArray") ?? Array()
array_all.removeSubrange(0..<10)
UserDefaults.standard.setValue(array_all, forKey: "eventArray")
print("finish")
}
}
}
这将同时对所有 10 个网络呼叫进行排队。调用并跟踪有多少个活动的异步网络调用。块内的代码将在所有 10 次网络调用完成(或错误)后调用。enter
leave
group.notify
评论
wait
signal