我有一个函数,它依次执行四个函数。棘手的部分似乎是让它们以正确的顺序执行。 function1 完成后,我想执行 function2 和 function3,它们可以同时运行。当 function2 和 function3 都完成时,我想运行 function4。
考虑:
func initializeMe() {
Task {
await loadMyData()
await loadMyLikes()
await loadMyAdmirers()
loadMyFriends()
}
}
流程应该是:
loadMyData()
从 Firestore 数据库加载用户数据,其中包含一个名为 likes 的数组,其中充满了用户 ID。
loadMyLikes()
根据 loadMyData()
中加载的点赞数组从 Firestore 加载用户
loadMyAdmirers()
也会加载用户,这次是在其他用户喜欢的地方寻找当前用户的id
loadMyFriends()
查找 myLikes
和 myAdmirers
共有的用户 ID。
并发对我来说很困难,我感觉我可能也需要这里的完成处理程序。任何建议将不胜感激。
如果您希望
loadMyLikes
和 loadMyAdmirers
同时运行,有两种常见模式。
withTaskGroup
,或 withDiscardingTaskGroup
:
func initializeMe() async {
await loadMyData()
await withDiscardingTaskGroup { [self] group in
group.addTask { await loadMyLikes() }
group.addTask { await loadMyAdmirers() }
}
loadMyFriends()
}
async let
:
func initializeMe() async {
await loadMyData()
async let likes: Void = loadMyLikes()
await loadMyAdmirers()
await likes
await admirers
loadMyFriends()
}
这两者都会:
await loadMyData()
;loadMyLikes
和 loadMyAdmirers
;和loadMyFriends
。两个最终观察结果:
就我个人而言,我会对在该函数中隐藏非结构化并发(
Task {…}
)持谨慎态度。调用者无法知道它何时完成。您也将失去取消的可能性。
在上面,我将其设为
async
函数,如果我确实需要从非 async
上下文进行桥接,我个人会在调用 initializeMe
的地方执行此操作,而不是在这里。随意做任何你想做的事情,但要对隐藏非结构化并发的影响非常敏感(或者至少在不做保存Task
的先决开销的情况下这样做,编写一些取消处理程序代码,弄清楚如何更新UI 与结果等)。
这里根本没有足够的信息来为您提供有关此主题的进一步建议(并且超出了本问题的范围),但是,简而言之,请小心非结构化并发。
您显然将这些函数的结果存储在属性中。有时我们想这样做(以便我们可以在更新信息出现时观察数据变化),但通常我们不会这样做。
例如,当
loadMyData
完成后,但我们还没有完成其他三个方法,UI 中要显示什么?没有点赞/崇拜者/朋友的数据?或者什么都不做,直到一切都完成?
底线,另一种方法是以这样的方式编写这些函数:它们不更新属性,而是
return
各自的结果。我们可以将其保存在局部变量中,并且仅在所有四种方法完成后才使用本地存储的结果更新属性。
这完全取决于你,但我想至少让你注意这种替代方法。