同时使用"withTaskGroup"和"async let"



以下是我如何使用withTaskGroup的简化版本:

let allResults = await withTaskGroup(of: ([Double], Float, Float, Int).self,
returning: FinalResult.self,
body: { taskGroup in
for operation in operations {
taskGroup.addTask { @MainActor in
let value = await operation.execute()
return value
}
}

// Collect child task results here...
})

execute函数看起来如下,其中过程包括相当密集的数学计算任务,如机器学习模型的特征提取:

func execute() async -> ([Double], Float, Float, Int) {
async let result0: [Double] = process0() ?? []
async let result1: Float = process1() ?? -1
async let result2: Float = process2()
async let result3: Int = process3()
return (await result0, await result1, await result2, await result3)
}

我遇到的问题是,最终的结果是不一致的,有时我得到适当的结果,有时不是。一个例子是,有时我得到一个512个特征(数组长度)的全零数组,而它们应该是非零数字。相反,如果我简单地使用for loop而不是withTaskGroup,结果似乎更一致。

所以我想知道withTaskGroupasync let一起使用是否有任何后果,因为这是并行的并行。与并发性不同,我对并行性的理解是分配CPU的每个核心来同时处理任务,但是如果我提供4个operations,这意味着4 x 4 = 16个并行进程,这比可用的核心数量要多。

这绝对不是问题所在。问题更有可能是您在process1()等中的代码不是线程安全的(例如,依赖于从非线程安全的属性读取的数据,或者以无效的方式操作返回的Array)。如果您正确地编写了代码,那么超过内核数量并不会导致逻辑问题。它可能会导致性能问题,这取决于许多因素,但它不会导致正确性问题。

你可能想要打开"严格并发检查";在您的构建设置中,这可以帮助您发现错误。(它也可以在Foundation中发现很多你无法修复的问题,所以有时最好在独立的代码或较小的项目中使用它。)

相关内容

  • 没有找到相关文章

最新更新