使用调度组时如何使公共资源线程安全?
How to make a common resource thread safe when using dispatch group?
我有一个 class 用户,每次用户打开应用程序时都需要更新该用户
class User : NSObject, NSCoding {
var vehicles : [Vehicles]
var bankaccounts : [BankAccounts]
var friends : [Friends]
}
在我的主屏幕 ViewController 中,我有一个函数可以使用 3 个 Alamofire 请求从后端获取数据。最后,我将数据保存在 UserDefaults 中。 DispatchGroup 是我想到的第一个实现这个的东西。这是代码
func loadUserData {
var user = User()
let userDataDispatchGroup = DispatchGroup()
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.vehicles array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.bankaccounts array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.friends array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.notify(queue: .main) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: user)
UserDefaults.standard.set(encodedData, forKey: "user")
}
}
但是我不清楚我的用户对象的线程安全性。由于它将在三个不同的回调中更新,线程安全在这里会成为一个问题吗?如果是,解决问题的最佳方法是什么?我正在考虑使用 DispatchSemaphore。但我不确定这是否是正确的方法。
您问的是:
But I am not clear about the thread-safety of my user object. Since it will be updated in three different callbacks, would thread safety be an issue here?
您的代码片段中没有线程安全问题,因为 Alamofire 在主线程上调用其完成处理程序。他们这样做是为了帮助减轻多线程问题。在这种情况下不需要任何 DispatchQueue.main.async
。作为 Alamofire documentation says:
Closures passed to response handlers are executed on the .main
queue by default, but a specific DispatchQueue
can be passed on which to execute the closure.
所以除非你做了一些不寻常的事情(比如用一些并发的 DispatchQueue
覆盖默认的 .main
队列),Alamofire 将 运行 它在主线程上的完成处理程序,减轻线程安全问题。
如果您使用的 API 未在主线程上调用其完成处理程序(例如 URLSession.shared
在后台队列上调用其完成处理程序),则可能会有问题,但不是与 Alamofire。 (甚至 URLSession
使用串行后台队列,因此使用您更新局部变量的模式不会有问题。)
最重要的是,只要您不是同时来自多个线程的 mutating/accessing 变量,线程安全问题就会在很大程度上得到缓解。
我有一个 class 用户,每次用户打开应用程序时都需要更新该用户
class User : NSObject, NSCoding {
var vehicles : [Vehicles]
var bankaccounts : [BankAccounts]
var friends : [Friends]
}
在我的主屏幕 ViewController 中,我有一个函数可以使用 3 个 Alamofire 请求从后端获取数据。最后,我将数据保存在 UserDefaults 中。 DispatchGroup 是我想到的第一个实现这个的东西。这是代码
func loadUserData {
var user = User()
let userDataDispatchGroup = DispatchGroup()
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.vehicles array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.bankaccounts array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.enter()
AF.request(...).responseJSON {
//update the user.friends array
userDataDispatchGroup.leave()
}
userDataDispatchGroup.notify(queue: .main) {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: user)
UserDefaults.standard.set(encodedData, forKey: "user")
}
}
但是我不清楚我的用户对象的线程安全性。由于它将在三个不同的回调中更新,线程安全在这里会成为一个问题吗?如果是,解决问题的最佳方法是什么?我正在考虑使用 DispatchSemaphore。但我不确定这是否是正确的方法。
您问的是:
But I am not clear about the thread-safety of my user object. Since it will be updated in three different callbacks, would thread safety be an issue here?
您的代码片段中没有线程安全问题,因为 Alamofire 在主线程上调用其完成处理程序。他们这样做是为了帮助减轻多线程问题。在这种情况下不需要任何 DispatchQueue.main.async
。作为 Alamofire documentation says:
Closures passed to response handlers are executed on the
.main
queue by default, but a specificDispatchQueue
can be passed on which to execute the closure.
所以除非你做了一些不寻常的事情(比如用一些并发的 DispatchQueue
覆盖默认的 .main
队列),Alamofire 将 运行 它在主线程上的完成处理程序,减轻线程安全问题。
如果您使用的 API 未在主线程上调用其完成处理程序(例如 URLSession.shared
在后台队列上调用其完成处理程序),则可能会有问题,但不是与 Alamofire。 (甚至 URLSession
使用串行后台队列,因此使用您更新局部变量的模式不会有问题。)
最重要的是,只要您不是同时来自多个线程的 mutating/accessing 变量,线程安全问题就会在很大程度上得到缓解。