我在某处读到函数式编程适合利用计算中的多核趋势.我真的不明白这个主意.它与lambda演算和von neumann架构有关吗?
功能编程最小化或消除副作用,因此更适合分布式编程.即多核处理.
换句话说,拼图的许多部分可以在不同的核心上同时独立解决,而不必担心一个操作影响另一个操作几乎与其他编程风格一样多.
处理并行处理最困难的事情之一是锁定数据结构以防止损坏.如果两个线程同时改变数据结构而没有完全锁定,则可能导致从无效数据到死锁的任何事情.
相反,函数式编程语言倾向于强调不可变数据.任何状态都与逻辑分开,一旦创建了数据结构,就无法修改.锁定的需求大大减少.
另一个好处是,一些非常容易并行化的过程(如迭代)被抽象为函数.在C++中,您可能有一个for循环,它对列表中的每个项目运行一些数据处理.但编译器无法知道这些操作是否可以安全地并行运行 - 可能一个操作的结果取决于之前的操作.当使用map()
或reduce()
使用函数时,编译器可以知道调用之间没有依赖关系.因此可以同时处理多个项目.
我已经读到某个地方,函数式编程适合利用计算中的多核趋势......我并没有真正理解.它与lambda演算和von neumann架构有关吗?
您引用的信念背后的论点是纯函数式编程控制副作用,这使得引入并行性更容易和更安全,因此,纯函数式编程语言在多核计算机环境中应该是有利的.
不幸的是,这一信念早已被证明有以下几个原因:
纯功能数据结构的绝对性能很差.因此,纯粹的函数式编程是性能环境中错误方向的一个重要的初始步骤(这是并行编程的唯一目的).
纯功能数据结构严重缩放,因为它们会强调共享资源,包括分配器/ GC和主内存带宽.因此,随着核心数量的增加,并行化的纯功能程序通常会获得较差的加速.
纯粹的功能编程使性能变得不可预测.因此,真正的纯功能程序在并行化时通常会看到性能下降,因为粒度实际上是随机的.
例如,Haskell社区经常引用的混合双线快速入口通常比用F#这样的更传统的语言编写的真实就地快速入口慢几千倍.此外,尽管您可以轻松地并行化优雅的Haskell程序,但您不太可能看到任何性能改进,因为所有不必要的复制使得单个核心使多核机器的整个主存储器带宽饱和,从而使并行性变得毫无价值.实际上,没有人能够在Haskell中编写任何具有竞争性的通用并行排序.Haskell标准库提供的最先进的排序通常比传统替代品慢几百倍.
然而,函数式编程作为强调使用第一类函数的风格的更常见定义实际上在多核编程的上下文中实际上非常有用,因为这种范例对于并行程序的因子分解是理想的.例如,Parallel.For
从System.Threading.Tasks
.NET 4中的命名空间中查看新的高阶函数.
当没有副作用时,评估的顺序无关紧要.然后可以并行地评估表达式.
基本论点是很难自动并行化C/C++等语言,因为函数可以设置全局变量.考虑两个函数调用:
a = foo(b, c); d = bar(e, f);
虽然foo和bar没有共同的参数,并且一个不依赖于另一个的返回代码,但它们仍然可能具有依赖性,因为foo可能设置一个全局变量(或其他副作用),而bar依赖于它.
函数式语言保证foo和bar是独立的:没有全局变量,也没有副作用.因此,foo和bar可以安全地在不同的核心上运行,无需程序员干预.