I use semaphore and DispatchGroup deal with the concurrency network.It's working fine in the demo.But it's not working after I copy the code to the project.Can anyone find the problem?
demo:
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)
}
and the demo result:
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
project:
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")
}
}
}
and the project result:
finish
successs=2
successs=1
successs=0
successs=3
successs=5
successs=4
successs=7
successs=6
successs=8
successs=9
I can't find the way deal with the problem cause the demo code working fine. Does anybody can find the reason to work out this?
You have several issues. Your demo doesn't actually simulate your real code because your demo
getRequestWithCallbackisn't actually asynchronous like the call toMCNetwork.share.requestis. If you madegetRequestWithCallbackto be asynchronous then you would find that your demo would fail like your real code.The first issue is that your semaphore isn't doing anything so you may as well remove all use of the semaphore.
The second, and more important, issue is that you should not use
asyncto call asynchronous code like you do in your real code. The reason the real code fails is because the loop completes immediately and all calls toasynccomplete long before the calls toMCNetwork.share.requesthave a chance to run. In the demo, sincegetRequestWithCallbackisn't asynchronous, the calls toasyncdon't complete untilgetRequestWithCallbackreturns (after the sleep).Here's one way to refactor your real code:
This will queue up all 10 network calls concurrently. The calls to
enterandleavekeep track of how many active async network calls there are. The code inside thegroup.notifyblock will be called after all 10 network calls complete (or error).