我试图将Firebase操作从旧的完成处理程序重构到新的Task.init()
,但现在似乎花费了更长的时间。我做错了什么吗?等待调用没有同时完成吗(这就是我同时调用这两个操作并使用完成处理程序方法计算完成了多少个操作的原因)?对于可能导致执行时间变慢的原因,您有什么建议吗?
先谢谢你了。
1.完井装卸机接近(0.73s)
以前我有过这种方法:
extension Firebase {
static func getAll<T: Decodable>(_ subCollection: SubCollection,
completion: @escaping (_ result: [T]?, _ error: Error?) -> Void) {
db.collection("userData").document(currentUser!.uid).collection("\(subCollection)").getDocuments(completion: { (querySnapshot, error) in
var documents: [T] = []
if let error { print(error.localizedDescription) }
if let querySnapshot {
for document in querySnapshot.documents {
if let decodedDocument = try? document.data(as: T.self) { documents.append(decodedDocument) }
else { print("Failed to decode a retrieved document of type \(T.self) at getAll") }
}
}
completion(documents, error)
AppNotification.post(.firebseOperationCompleted)
})
}
}
我会这样使用它:
class Loading: UIViewController {
var error: Error?
var operationsCompleted = 0
let start = CFAbsoluteTimeGetCurrent()
private func fetchData() {
operationsCompleted = 0
Firebase.getAll(.goals, completion: { (results: [Goal]?, error) in
if let results { UltraDataStorage.goals = results }
if let error { self.error = error }
self.operationsCompleted += 1
})
Firebase.getAll(.ideas, completion: { (results: [Idea]?, error) in
if let results { UltraDataStorage.ideas = results }
if let error { self.error = error }
self.operationsCompleted += 1
})
@objc func advanceWhenOperationsComplete(){
print("Took \(CFAbsoluteTimeGetCurrent() - self.start) seconds")
if operationsCompleted == 2 {
// Proceed if error is nil
}
}
override func viewDidLoad() {
fetchData()
AppNotification.observe(handler: self, name: .firebseOperationCompleted, function: #selector(advanceWhenOperationsComplete))
}
}
Task.init()
接近(1.14秒)
现在,我更新了getAll
函数:
extension Firebase {
static func getAll<T: Decodable>(_ subCollection: SubCollection) async -> Result<[T], Error> {
do {
let documents = try await db.collection("userData").document(currentUser!.uid).collection("\(subCollection)").getDocuments()
var decodedDocuments: [T] = []
for document in documents.documents {
if let decodedDocument = try? document.data(as: T.self) { decodedDocuments.append(decodedDocument) }
else { print("Failed to decode a retrieved document of type \(T.self) at getAll") }
}
return.success(decodedDocuments)
}
catch { return.failure(error) }
}
}
我现在这样称呼它
class Loading: UIViewController {
var error: Error?
let start = CFAbsoluteTimeGetCurrent()
private func fetchData() {
Task.init(operation: {
let goalsResult: Result<[Goal], Error> = await Firebase.getAll(.goals)
switch goalsResult {
case .success(let goals): UltraDataStorage.goals = goals
case .failure(let error): self.error = error
}
let ideasResult: Result<[Idea], Error> = await Firebase.getAll(.ideas)
switch ideasResult {
case .success(let ideas): UltraDataStorage.ideas = ideas
case .failure(let error): self.error = error
}
DispatchQueue.main.async {
self.advanceWhenOperationsComplete()
}
})
}
func advanceWhenOperationsComplete(){
print("Took \(CFAbsoluteTimeGetCurrent() - self.start) seconds")
// Proceed when the async operations are completed
}
override func viewDidLoad() {
fetchData()
}
}
1条答案
按热度按时间wrrgggsh1#
性能差异可能是由于完成处理程序模式并发地运行请求,而
async
-await
副本是按顺序执行的。后者在启动下一个异步请求之前等待第一个异步请求的结果。要使它们并发运行,可以使用
async let
模式(请参见SE-0317)或使用任务组:(这些可能不是100%正确的,因为我没有实现所有这些类型和方法,因此无法编译它,但希望它说明了这个想法。值得注意的是,我对
UltraDataStorage
的线程安全性感到紧张,特别是在任务组示例中。但这超出了本问题的范围。)总之,
async let
是一种并发运行任务的直观方式,在处理固定的、有限数量的异步任务时最有用。任务组在处理可变数量的任务时很有用。这里不是这种情况,但为了完整起见,我将其包括在内。请注意,我已经删除了
Result<[T], Error>
类型,而代之以throw
错误。