带有信号量用例的重大调度
iOS,swift,GCD,信号量
我今天遇到了一个问题,很想分享一下,以防有人遇到。
故事
我正在快速构建一个API,该API通过称为SendRequest的方法在内部向后端发送GET和POST请求。 此方法还可以交互并从数据库中获取数据(核心数据)。
在SendREquest方法内部,有一个GetLatestUpdateTime调用,该调用将GET请求发送到服务器并检索Date( LatestTime ),然后我从该Date( latestTime )之后的数据库中获取所有记录,然后将这些记录上传到POST中的服务器上。使用Alamofire提出要求。
问题
在非常特殊的情况下,可能在同一时刻多次调用SendRequest方法。 GetLatestUpdateTime将返回相同的lastTime对象,然后从数据库中获取相同的dbObject ,最后将这些相同的dbObjects上传到服务器。 重复 !!!
可怕的重复将发生,而这不应该发生。
解
在上一个调用完成之前,必须存在防止再次调用SendRequest方法的方法。 因此,调用是同步的,当然不会阻塞主线程。
GCD
与我一起工作的方法是将Dispatch Queues与Semaphore一起使用 。
- 首先,我创建了一个调度队列
var reportQueue = dispatch_queue_create(“ com.myapp.report”,
DISPATCH_QUEUE_SERIAL);
2.和信号灯
让信号量:dispatch_semaphore_t = dispatch_semaphore_create(0);
零是这里的初始计数器,在我的情况下,我每次只想一次访问。
3.将sendRequest方法添加到队列
dispatch_async(self.reportQueue){
self.sendReport()
}
4.在sendRequest方法中
并在调用GetLatestUpdateTime API之后,添加信号量等待
dispatch_semaphore_wait(信号灯,DISPATCH_TIME_FOREVER);
这将使初始计数器减少为-1 ,下一次对该部分“ sendRequest”的调用将不得不等待 。
5. 完成请求后,我们会发出信号量
dispatch_semaphore_signal(self.semaphore);
这将使计数器再次增加为0 ,从而允许再次输入关键部分。
这就是sendRequest方法的样子
公共功能exitRegion(){
dispatch_async(self.reportQueue){
self.sendReport()
}
}
私人功能sendReport(){
httpClient.getLatestUpdatedDate(String(self.userId)){(latestDateTime,错误)在
如果让_ =错误{
debugPrint(“ \(#file),\(错误?.localizedDescription)”)
///如果请求失败
dispatch_semaphore_signal(self.semaphore);
返回
}
让地区报告:[ANARegion]? = self.analyticsDBManaer.findRegionsReportsAfterDate(latestDateTime)
让regionjson = regionReports?.map({$ 0.dictionary})
self.httpClient.postReport(regionsjson,完成:{(成功)在
如果成功{
self.analyticsDBManaer.clearDataBase()
///请求完成后,我们发出信号量
dispatch_semaphore_signal(self.semaphore);
}
})
}
dispatch_semaphore_wait(信号灯,DISPATCH_TIME_FOREVER);
}
- DISPATCH_TIME_FOREVER:-可以更改,因此,如果出现问题,我们不会永远阻塞线程,也无法发出信号,例如
let timeToWait = dispatch_time(DISPATCH_TIME_NOW,Int64(30 * NSEC_PER_SEC))
dispatch_semaphore_wait(semaphore,timeToWait);
正如我在谈论我的经验。 在调试时, timeToWait最好更高。
这是外观的可视化。
免责声明
理论解释和数字:p可能不是100%正确的,如果您进行了编辑,请发表评论。 谢谢。
感谢阅读,编码愉快。