为什么我不应该使用F#异步工作流来实现并行化?

Gna*_*nat 19 parallel-processing f# asynchronous task-parallel-library

我最近一直在学习F#,特别感兴趣的是它易于利用数据并行性.这个data |> Array.map |> Async.Parallel |> Async.RunSynchronously成语似乎很容易理解,直接使用并从中获得真正的价值.

那么为什么它async不是真正意图呢?Donald Syme本人表示,PLINQ和期货可能是更好的选择.我在这里读到的其他答案同意这一点以及推荐TPL.(PLINQ与上述内置函数似乎没什么不同,只要您使用F#Powerpack来获取PSeq函数.)

F#和函数式语言对此非常有意义,并且一些应用程序async并行性方面取得了巨大成功.

那么为什么我不应该async用来执行并行数据流程呢?通过编写并行async代码而不是使用PLINQ或TPL,我将失去什么?

Jon*_*rop 15

那么为什么我不应该使用异步来执行并行数据流程呢?

如果您拥有少量完全独立的非async任务和大量内核,那么使用async实现并行性没有任何问题.但是,如果您的任务以任何方式依赖,或者您拥有的任务多于核心,或者您async在代码中使用了太多,那么您将在桌面上留下很多性能,并且可以通过选择更多内容来做得更好并行编程的适当基础.

请注意,使用F#中的TPL可以更优雅地编写示例:

Array.Parallel.map f xs
Run Code Online (Sandbox Code Playgroud)

通过编写并行异步代码而不是使用PLINQ或TPL,我将失去什么?

您将失去编写缓存遗忘代码的能力,因此会遭受大量缓存未命中,因此,所有内核都会停止等待共享内存,这意味着多核上的可扩展性较差.

TPL建立在这样的思想之上:子任务应该以高概率在与父级相同的核心上执行,因此,重用相同的数据将会受益,因为它在本地CPU缓存中会很热.异步没有这样的保证.


Tom*_*cek 12

我写了重新实现同时使用一个C#TPL样本的文章TaskAsync,这也对两者之间的差别一些意见.你可以在这里找到它,还有一个更高级的基于异步的版本.

以下是第一篇文章的引用,它比较了两个选项:

两种可能的实现之间的选择取决于许多因素.异步工作流是专为F#设计的,因此它们更适合语言.它们为I/O绑定任务提供了更好的性能,并提供了更方便的异常处理.而且,顺序语法非常方便.另一方面,任务针对CPU绑定计算进行了优化,并且可以更轻松地从应用程序的其他位置访问计算结果,而无需显式缓存.