函数并行性的编程语言:f# vs Haskell。

时间:2022-09-11 09:31:04

Functional programming has immutable data structures and no side effect which are inherently suitable for parallel programming. I investigate how to exploit multicore computation in a functional language, and target production code for some numerical applications.

函数式编程具有不可变的数据结构,而且没有任何天生适合并行编程的副作用。我研究了如何在函数语言中开发多核计算,并针对一些数值应用程序开发目标生产代码。

F# has Microsoft behind its back, and its parallel constructs such as PLINQ, TPL, Async Workflow have been well-documented and shown some potentials. However, research about parallelism in Haskell is very active at the moment, and it posseses many nice features which haven't been supported by F# yet:

f#的背后有微软,它的并行结构,如PLINQ, TPL, Async工作流已经被充分的记录并且显示了一些潜力。然而,关于Haskell中并行性的研究目前非常活跃,它拥有许多尚未得到f#支持的好特性:

My question is which language I should choose for functional parallelism? If F# is chosen, are there any pointers to build up what they currently have in Haskell?

我的问题是,我应该选择哪种语言来实现功能并行?如果选择f#,是否有任何指针来构建他们当前在Haskell中所拥有的内容?

UPDATE:

更新:

I chose Simon's answer because it brought out some nice discussion about garbage collector, memory allocation and cache miss. I will stick to F#, and I think these answers are helpful for me to study functional parallelism.

我选择了Simon的答案,因为它引出了一些关于垃圾回收器、内存分配和缓存错误的讨论,我将坚持f#,我认为这些答案对我研究函数并行性很有帮助。

7 个解决方案

#1


49  

If the kind of code you have in mind allocates memory heavily, then you might find that the GHC garbage collector scales better than the .NET garbage collector. There's some anedcodal evidence that the .NET GC becomes a bottleneck when multiple threads are allocating heavily, and this is also a thorn in the side of most Java collectors too. On the other hand we've paid quite a lot of attention to achieving good locality and scalability in the GHC garbage collector - mainly because we have no choice, most idiomatic Haskell code allocates heavily anyway. I have benchmarks that allocate like crazy and keeping scaling beyond 24 cores.

如果您脑海中有这样的代码,那么您可能会发现,GHC垃圾收集器比。net垃圾收集器要好。有一些anedcodal的证据表明,当多个线程大量分配时,. net GC成为瓶颈,这也是大多数Java收集器的一根刺。另一方面,我们已经花了相当多的精力在GHC垃圾收集器中实现良好的位置和可伸缩性——主要是因为我们没有选择,大多数惯用的Haskell代码都分配得很重。我有一些基准,比如疯狂的分配和超过24个核心的扩展。

In Haskell note that you get a guarantee of determinism from the type system, which you don't get in F#.

在Haskell中,您可以从类型系统中获得确定性的保证,而这是您在f#中无法得到的。

You mentioned Data Parallel Haskell: a cautionary note here, it isn't ready for production use at the present time, although the DPH team are expecting that the forthcoming GHC 7.2.1 release will have a stable DPH implementation.

您提到的数据并行Haskell:这里有一个警告,目前还没有准备好用于生产,尽管DPH团队预计即将发布的GHC 7.2.1版本将会有一个稳定的DPH实现。

#2


21  

First of all, I agree with others that there is no objective answer.

首先,我同意其他人的观点,没有客观的答案。

However, I think that the idea of functional parallelism is a bit overrated. Surely, you can easily find data dependencies in your program and if you're processing lots of data, you can use some data-parallel library to easily and safely parallelize it. However, this can be done even in C# (using TPL and PLINQ) if you're a bit careful about what you're writing.

但是,我认为函数并行性的概念被高估了。当然,您可以很容易地在您的程序中找到数据依赖项,如果您正在处理大量数据,您可以使用一些数据并行库来轻松安全地并行化它。然而,如果您对您正在编写的内容有一点谨慎,即使在c#(使用TPL和PLINQ)中也可以做到这一点。

The problem is, that most of the programs don't need to be parallelized, because they simply don't do enough CPU-intensive work. For example, F# async solves (I think) more important problem of enabling asynchronous I/O, which is the reason for most "hangs" in connected applications. I think the popularity of Node.js demonstrates this importance quite nicely.

问题是,大多数程序不需要并行化,因为它们根本无法完成足够的cpu密集型工作。例如,f# async解决了(我认为)启用异步I/O的更重要的问题,这是连接应用程序中大多数“挂起”的原因。我认为节点的受欢迎程度。js很好地展示了这一重要性。

The real value of functional languages is in the expressivity of the language - you can easily define abstractions for your problem, write code in a more succinct way that is easier to understand, reason about and test. You get this in both F# and Haskell.

函数式语言的真正价值在于语言的表达性——您可以轻松地为您的问题定义抽象,以更简洁的方式编写代码,从而更容易理解、推理和测试。你可以在f#和Haskell中得到这个。

To answer your specific question about parallelism - I believe that the status of parallelism support in F# is more stable (but then, I'm an F# person). You can choose between async, TPL and (Erlang-inspired) F# agents (which are all quite stable libraries). On the Haskell side, there is still a lot of evolution going on. The most recent work is just few weeks old. I also find it easier to use parallelism in a language with clearly specified evaluation model, but that may be just my personal preference.

要回答关于并行性的具体问题,我相信f#中并行支持的状态更稳定(但是,我是一个f# person)。您可以在async、TPL和(Erlang-inspired) f#代理之间进行选择(它们都是相当稳定的库)。在Haskell方面,仍然有很多的进化。最近的工作只有几周的时间。我也发现在一种语言中使用并行性很容易,并且有明确的评估模型,但这可能只是我个人的偏好。

#3


20  

I'm going to get downvoted for this, but let me be the curmudgeon.

我将会对此投下反对票,但让我做一个坏脾气的人。

Functional languages are great. They change the way you think about decomposing problems, and they map incredibly well to certain kinds of problems. Every programmer should be familar with at least one functional programming language. But "functional languages are inherently good for parallel programming" is probably not the reason why.

函数式语言是伟大的。它们会改变你思考分解问题的方式,它们会映射到某些问题上。每个程序员都应该熟悉至少一种函数式编程语言。但是“函数式语言天生适合并行编程”,这可能不是原因。

It's worth noting that what is unquestionably the most successful parallel functional language of all time, Erlang, uses completely bog-standard message passing to implement its parallelism, and the connection between its functional nature and its parallelism is indirect at best.

值得注意的是,毫无疑问,所有时间中最成功的并行函数语言Erlang,使用完全的bog标准消息传递来实现它的并行性,并且它的函数性和并行性之间的联系充其量是间接的。

Twenty-five years ago, there was a huge push for functional languages, because the argument then seemed very compelling as well -- functional languages seemed a natural fit for the increasingly parallel architectures of the time. The argument was that compilers and runtimes would automatically be able to implement parallelism, due to the side-effect free nature of the languages. SISAL, which even then could be compiled into shared- and distributed- memory (!) executables was developed at this time, as was Haskell, as was ML, the the predecessor to Objective CAML and the other lanaguages in the ML family.

25年前,函数式语言有了巨大的推动力,因为当时的争论似乎也很有说服力——函数式语言似乎很自然地适合于日益并行的架构。其理由是编译器和运行时可以自动实现并行性,这是由于语言的副作用。SISAL甚至可以被编译成共享的和分布式的内存(!)可执行程序在这个时候被开发,正如Haskell所做的那样,它是ML,它的前身是Objective CAML的前身,以及ML家族中其他的lanaguages。

This is all just offered a bit of historical perspective. For literally a quarter of a century, functional-language advocates, including some of the brightest minds in the field, have been saying that functional languages' day in the sun was just around the corner, and that it's going to the be applicability to parallelism that is the killer app. And yet, here we are, with no one even having heard of SISAL; and I'm guessing that most readers of this post think of Haskell as a hot new language.

这只是提供了一点历史的视角。字面上四分之一个世纪以来,函数语言的支持者,包括一些最聪明的头脑,一直在说,函数式语言的一天,太阳刚刚在拐角处,那它会是适用于并行性是杀手级应用。然而,我们甚至没有人有听说过麻;我猜大多数读者都认为Haskell是一种热门的新语言。

It could well be, of course, that now with multicore considerations things have finally gotten so urgent that functional languages are really going to shine, or that this year will be the year that there's some breakthrough I can't even imagine which completely changes the landscape. This year could well be different than each of the 25 previous years. But it might not, too.

当然,现在有了多核的考虑,事情最终变得非常紧急,函数式语言真的会发光,或者今年将是有一些突破的一年,我甚至无法想象这完全改变了风景。今年很可能与前25年不同。但也可能不会。

The vast, vast, vast majority of parallel and concurrent code extant now, and well into the forseeable future, is not written in functional languages. If you're looking to learn about parallelism, by all means explore the mechanisms available in F#, Haskell etc; but don't limit yourself to those, is all I'm saying.

现在,大量的、巨大的、绝大多数的并行和并发代码,并在可预见的未来中,都不是用函数式语言编写的。如果你想学习并行性,那么你可以探索f#、Haskell等的机制;但不要局限于这些,我只是说。

#4


12  

The simple answer is that because both languages have solid support for parallelism and concurrency, this shouldn't be a factor in your decision on which language to use. I.e., there are much larger factors to take into consideration for a decision like that.

简单的回答是,因为这两种语言都有对并行性和并发性的可靠支持,所以在决定使用哪种语言时,这应该不是一个因素。即。有很多更大的因素需要考虑这样的决定。

#5


8  

There's no objective answer. For Haskell, there's a large body of active work, and no "one size fits all" approach. Instead, in Haskell, many different tools for achieving parallelism are provided. What's the status of multicore programming in Haskell?

没有客观的答案。对于Haskell来说,有大量的活动工作,没有“一种适合所有”的方法。相反,在Haskell中,提供了许多实现并行性的不同工具。Haskell中多核编程的状态是什么?

#6


8  

Functional programming has immutable data structures and no side effect which are inherently suitable for parallel programming.

函数式编程具有不可变的数据结构,而且没有任何天生适合并行编程的副作用。

That is a common misconception. Parallelism is solely about performance and purity degrades performance. So purely functional programming is not a good starting point if your objective is to get decent performance. In general, purity means more allocation and worse locality. In particular, purely functional data structures replace arrays with trees and that incurs many more allocations and places far more burden on the garbage collector.

这是一个普遍的误解。并行性只与性能和纯度降低性能有关。因此,如果您的目标是获得良好的性能,那么纯函数编程并不是一个好的起点。一般来说,纯洁意味着更多的分配和更坏的地方。特别是,纯功能的数据结构用树替换数组,这会增加更多的分配,并给垃圾收集器带来更多的负担。

For example, measure the performance of the elegant purely functional "quicksort" in Haskell. Last I checked, it was thousands of times slower than the conventional imperative solution on my machine.

例如,在Haskell中度量优雅的纯函数“快速排序”的性能。最后我检查了一下,它比我的机器上常规的命令解决方案慢了数千倍。

Also, nobody has ever managed to implement an efficient dictionary data structure (pure or impure) or an efficient purely-functional sort in Haskell and nobody has figured out how to write an asymptotically efficient persistent disjoint set data structure and there is no known way to implement other basic data structures like purely functional weak dictionaries!

也没有人设法实现一个高效的字典数据结构(纯或不洁净的)或者一个高效的纯函数式Haskell和没有人想出了如何编写一个渐近有效持久不相交集合数据结构和没有已知的方法来实现纯粹的功能弱等基本数据结构字典!

Moreover, although it is theoretically possible to write impure code in Haskell the GC is heavily optimized for pure code at the expense of the performance of mutation. For example, GHC's hash table is still 26× slower than .NET's. Historically, the performance of mutation was considered so unimportant in Haskell that writing a single pointer to an array was an O(n) operation in GHC for five years.

此外,虽然理论上可以在Haskell中编写不纯代码,但GC对纯代码进行了大量优化,但代价是发生了突变。例如,GHC的哈希表仍然是26日×慢于。net。从历史上看,在Haskell中,突变的性能被认为是不重要的,在GHC中编写一个指向数组的指针是5年的O(n)操作。

I investigate how to exploit multicore computation in a functional language, and target production code for some numerical applications.

我研究了如何在函数语言中开发多核计算,并针对一些数值应用程序开发目标生产代码。

The best way I have found is to learn how to write decent parallel programs for multicores in the imperative style (study Cilk, in particular) and then factor the code using first-class functions and tail call elimination into the impure functional style.

我发现的最好的方法是学习如何在命令式风格(特别是研究Cilk)中编写适合多核的并行程序,然后使用一流的函数和尾调用消除器将代码分解为不纯的函数样式。

This means cache oblivious data structures and algorithms. Nobody has ever done this in Haskell. Indeed, none of the research published on parallel Haskell to-date has even mentioned the essential concept of cache complexity. Furthermore, although it is widely known that non-strict (aka lazy) evaluation renders space consumption unpredictable, it is not yet widely appreciated that this same problem renders scalability wildly unpredictable on multicores.

这意味着缓参无关数据结构和算法。在Haskell中从来没有人这样做过。实际上,在并行Haskell到date上发表的研究中,没有一个提到缓存复杂性的基本概念。此外,尽管众所周知,非严格(即懒惰)的评估使空间消费难以预测,但人们还没有普遍认识到,这一问题在多核领域造成了难以预测的可伸缩性。

F# has Microsoft behind its back, and its parallel constructs such as PLINQ, TPL, Async Workflow have been well-documented and shown some potentials.

f#的背后有微软,它的并行结构,如PLINQ, TPL, Async工作流已经被充分的记录并且显示了一些潜力。

They are well beyond showing potential. Thousands of commercial applications are built upon those industrial-strength foundations.

它们远远超出了显示潜力的程度。成千上万的商业应用建立在这些工业基础之上。

However, research about parallelism in Haskell is very active at the moment, and it posseses many nice features which haven't supported by F# yet:

然而,关于Haskell中并行性的研究目前非常活跃,它拥有许多尚未被f#支持的好特性:

Why do you assume they are "nice features"?

为什么你认为它们是“好特性”?

I suggest reading Simon Marlow's latest paper about this:

我建议阅读西蒙·马洛的最新论文:

"...a combination of practical experience and investigation has lead us to conclude that this approach is not without drawbacks. In a nutshell, the problem is this: achieving parallelism with par requires that the programmer understand operational properties of the language that are at best implementation-defined (and at worst undefined). This makes par difficult to use, and pitfalls abound — new users have a high failure rate..."

“…结合实际经验和调查,我们得出结论,这种方法并非没有缺点。简而言之,问题是这样的:使用par实现并行性要求程序员理解最佳实现定义的语言的操作属性(在最糟糕的情况下是未定义的)。这使得使用起来很困难,而且有很多缺陷——新用户的失败率很高……

My question is which language should I choose for functional parallelism?

我的问题是,我应该选择哪种语言来实现功能并行?

I'd advise against parallel purely functional code for production because it is a complete wild card. Assuming you're happy to sacrifice some purity in order to attain competitive performance, I use and recommend F#.

我建议不要使用并行的纯函数代码,因为它是一个完整的通配符。假设你愿意牺牲一些纯度来获得竞争性能,我使用并推荐f#。

#7


6  

Haskell's purity means that it makes a clear distinction between parallel processing and concurrency.

Haskell的纯度意味着它在并行处理和并发之间有明显的区别。

  • If you are looking to speed up your big data-crunching application by distributing the work over multiple cores then you want parallel processing, which means "par" and its derivatives. By careful use of these constructs you can have your CPU-intensive pure function run N times faster on N cores whilst being sure that you haven't changed the meaning of the original code or introduced non-determinism into your program.

    如果您希望通过将工作分配到多个核心来加速您的大数据处理应用程序,那么您需要并行处理,这意味着“par”及其派生。通过仔细地使用这些结构,您可以让cpu密集型的纯函数在N个内核上运行N倍快,同时确保您没有更改原始代码的含义,或者将不确定性引入到您的程序中。

  • On the other hand if you want your program to interact with multiple entities in the outside world, interleaving communications from different entities but still having some degree of shared resources, then you want concurrency, which means using "fork" and some combination of STM and TVars. STM gives you nice transactional semantics, which goes a long way towards eliminating race conditions and other nasties of concurrency. You do need to pay attention to collision frequency and retry rates though.

    另一方面,如果您希望您的程序与外部世界中的多个实体交互,将来自不同实体的通信联系起来,但仍然拥有一定程度的共享资源,那么您需要并发性,这意味着使用“fork”和一些STM和TVars的组合。STM为您提供了良好的事务性语义,这对于消除竞争条件和其他并发性问题有很长的路要走。但是你需要注意碰撞频率和重试率。

#1


49  

If the kind of code you have in mind allocates memory heavily, then you might find that the GHC garbage collector scales better than the .NET garbage collector. There's some anedcodal evidence that the .NET GC becomes a bottleneck when multiple threads are allocating heavily, and this is also a thorn in the side of most Java collectors too. On the other hand we've paid quite a lot of attention to achieving good locality and scalability in the GHC garbage collector - mainly because we have no choice, most idiomatic Haskell code allocates heavily anyway. I have benchmarks that allocate like crazy and keeping scaling beyond 24 cores.

如果您脑海中有这样的代码,那么您可能会发现,GHC垃圾收集器比。net垃圾收集器要好。有一些anedcodal的证据表明,当多个线程大量分配时,. net GC成为瓶颈,这也是大多数Java收集器的一根刺。另一方面,我们已经花了相当多的精力在GHC垃圾收集器中实现良好的位置和可伸缩性——主要是因为我们没有选择,大多数惯用的Haskell代码都分配得很重。我有一些基准,比如疯狂的分配和超过24个核心的扩展。

In Haskell note that you get a guarantee of determinism from the type system, which you don't get in F#.

在Haskell中,您可以从类型系统中获得确定性的保证,而这是您在f#中无法得到的。

You mentioned Data Parallel Haskell: a cautionary note here, it isn't ready for production use at the present time, although the DPH team are expecting that the forthcoming GHC 7.2.1 release will have a stable DPH implementation.

您提到的数据并行Haskell:这里有一个警告,目前还没有准备好用于生产,尽管DPH团队预计即将发布的GHC 7.2.1版本将会有一个稳定的DPH实现。

#2


21  

First of all, I agree with others that there is no objective answer.

首先,我同意其他人的观点,没有客观的答案。

However, I think that the idea of functional parallelism is a bit overrated. Surely, you can easily find data dependencies in your program and if you're processing lots of data, you can use some data-parallel library to easily and safely parallelize it. However, this can be done even in C# (using TPL and PLINQ) if you're a bit careful about what you're writing.

但是,我认为函数并行性的概念被高估了。当然,您可以很容易地在您的程序中找到数据依赖项,如果您正在处理大量数据,您可以使用一些数据并行库来轻松安全地并行化它。然而,如果您对您正在编写的内容有一点谨慎,即使在c#(使用TPL和PLINQ)中也可以做到这一点。

The problem is, that most of the programs don't need to be parallelized, because they simply don't do enough CPU-intensive work. For example, F# async solves (I think) more important problem of enabling asynchronous I/O, which is the reason for most "hangs" in connected applications. I think the popularity of Node.js demonstrates this importance quite nicely.

问题是,大多数程序不需要并行化,因为它们根本无法完成足够的cpu密集型工作。例如,f# async解决了(我认为)启用异步I/O的更重要的问题,这是连接应用程序中大多数“挂起”的原因。我认为节点的受欢迎程度。js很好地展示了这一重要性。

The real value of functional languages is in the expressivity of the language - you can easily define abstractions for your problem, write code in a more succinct way that is easier to understand, reason about and test. You get this in both F# and Haskell.

函数式语言的真正价值在于语言的表达性——您可以轻松地为您的问题定义抽象,以更简洁的方式编写代码,从而更容易理解、推理和测试。你可以在f#和Haskell中得到这个。

To answer your specific question about parallelism - I believe that the status of parallelism support in F# is more stable (but then, I'm an F# person). You can choose between async, TPL and (Erlang-inspired) F# agents (which are all quite stable libraries). On the Haskell side, there is still a lot of evolution going on. The most recent work is just few weeks old. I also find it easier to use parallelism in a language with clearly specified evaluation model, but that may be just my personal preference.

要回答关于并行性的具体问题,我相信f#中并行支持的状态更稳定(但是,我是一个f# person)。您可以在async、TPL和(Erlang-inspired) f#代理之间进行选择(它们都是相当稳定的库)。在Haskell方面,仍然有很多的进化。最近的工作只有几周的时间。我也发现在一种语言中使用并行性很容易,并且有明确的评估模型,但这可能只是我个人的偏好。

#3


20  

I'm going to get downvoted for this, but let me be the curmudgeon.

我将会对此投下反对票,但让我做一个坏脾气的人。

Functional languages are great. They change the way you think about decomposing problems, and they map incredibly well to certain kinds of problems. Every programmer should be familar with at least one functional programming language. But "functional languages are inherently good for parallel programming" is probably not the reason why.

函数式语言是伟大的。它们会改变你思考分解问题的方式,它们会映射到某些问题上。每个程序员都应该熟悉至少一种函数式编程语言。但是“函数式语言天生适合并行编程”,这可能不是原因。

It's worth noting that what is unquestionably the most successful parallel functional language of all time, Erlang, uses completely bog-standard message passing to implement its parallelism, and the connection between its functional nature and its parallelism is indirect at best.

值得注意的是,毫无疑问,所有时间中最成功的并行函数语言Erlang,使用完全的bog标准消息传递来实现它的并行性,并且它的函数性和并行性之间的联系充其量是间接的。

Twenty-five years ago, there was a huge push for functional languages, because the argument then seemed very compelling as well -- functional languages seemed a natural fit for the increasingly parallel architectures of the time. The argument was that compilers and runtimes would automatically be able to implement parallelism, due to the side-effect free nature of the languages. SISAL, which even then could be compiled into shared- and distributed- memory (!) executables was developed at this time, as was Haskell, as was ML, the the predecessor to Objective CAML and the other lanaguages in the ML family.

25年前,函数式语言有了巨大的推动力,因为当时的争论似乎也很有说服力——函数式语言似乎很自然地适合于日益并行的架构。其理由是编译器和运行时可以自动实现并行性,这是由于语言的副作用。SISAL甚至可以被编译成共享的和分布式的内存(!)可执行程序在这个时候被开发,正如Haskell所做的那样,它是ML,它的前身是Objective CAML的前身,以及ML家族中其他的lanaguages。

This is all just offered a bit of historical perspective. For literally a quarter of a century, functional-language advocates, including some of the brightest minds in the field, have been saying that functional languages' day in the sun was just around the corner, and that it's going to the be applicability to parallelism that is the killer app. And yet, here we are, with no one even having heard of SISAL; and I'm guessing that most readers of this post think of Haskell as a hot new language.

这只是提供了一点历史的视角。字面上四分之一个世纪以来,函数语言的支持者,包括一些最聪明的头脑,一直在说,函数式语言的一天,太阳刚刚在拐角处,那它会是适用于并行性是杀手级应用。然而,我们甚至没有人有听说过麻;我猜大多数读者都认为Haskell是一种热门的新语言。

It could well be, of course, that now with multicore considerations things have finally gotten so urgent that functional languages are really going to shine, or that this year will be the year that there's some breakthrough I can't even imagine which completely changes the landscape. This year could well be different than each of the 25 previous years. But it might not, too.

当然,现在有了多核的考虑,事情最终变得非常紧急,函数式语言真的会发光,或者今年将是有一些突破的一年,我甚至无法想象这完全改变了风景。今年很可能与前25年不同。但也可能不会。

The vast, vast, vast majority of parallel and concurrent code extant now, and well into the forseeable future, is not written in functional languages. If you're looking to learn about parallelism, by all means explore the mechanisms available in F#, Haskell etc; but don't limit yourself to those, is all I'm saying.

现在,大量的、巨大的、绝大多数的并行和并发代码,并在可预见的未来中,都不是用函数式语言编写的。如果你想学习并行性,那么你可以探索f#、Haskell等的机制;但不要局限于这些,我只是说。

#4


12  

The simple answer is that because both languages have solid support for parallelism and concurrency, this shouldn't be a factor in your decision on which language to use. I.e., there are much larger factors to take into consideration for a decision like that.

简单的回答是,因为这两种语言都有对并行性和并发性的可靠支持,所以在决定使用哪种语言时,这应该不是一个因素。即。有很多更大的因素需要考虑这样的决定。

#5


8  

There's no objective answer. For Haskell, there's a large body of active work, and no "one size fits all" approach. Instead, in Haskell, many different tools for achieving parallelism are provided. What's the status of multicore programming in Haskell?

没有客观的答案。对于Haskell来说,有大量的活动工作,没有“一种适合所有”的方法。相反,在Haskell中,提供了许多实现并行性的不同工具。Haskell中多核编程的状态是什么?

#6


8  

Functional programming has immutable data structures and no side effect which are inherently suitable for parallel programming.

函数式编程具有不可变的数据结构,而且没有任何天生适合并行编程的副作用。

That is a common misconception. Parallelism is solely about performance and purity degrades performance. So purely functional programming is not a good starting point if your objective is to get decent performance. In general, purity means more allocation and worse locality. In particular, purely functional data structures replace arrays with trees and that incurs many more allocations and places far more burden on the garbage collector.

这是一个普遍的误解。并行性只与性能和纯度降低性能有关。因此,如果您的目标是获得良好的性能,那么纯函数编程并不是一个好的起点。一般来说,纯洁意味着更多的分配和更坏的地方。特别是,纯功能的数据结构用树替换数组,这会增加更多的分配,并给垃圾收集器带来更多的负担。

For example, measure the performance of the elegant purely functional "quicksort" in Haskell. Last I checked, it was thousands of times slower than the conventional imperative solution on my machine.

例如,在Haskell中度量优雅的纯函数“快速排序”的性能。最后我检查了一下,它比我的机器上常规的命令解决方案慢了数千倍。

Also, nobody has ever managed to implement an efficient dictionary data structure (pure or impure) or an efficient purely-functional sort in Haskell and nobody has figured out how to write an asymptotically efficient persistent disjoint set data structure and there is no known way to implement other basic data structures like purely functional weak dictionaries!

也没有人设法实现一个高效的字典数据结构(纯或不洁净的)或者一个高效的纯函数式Haskell和没有人想出了如何编写一个渐近有效持久不相交集合数据结构和没有已知的方法来实现纯粹的功能弱等基本数据结构字典!

Moreover, although it is theoretically possible to write impure code in Haskell the GC is heavily optimized for pure code at the expense of the performance of mutation. For example, GHC's hash table is still 26× slower than .NET's. Historically, the performance of mutation was considered so unimportant in Haskell that writing a single pointer to an array was an O(n) operation in GHC for five years.

此外,虽然理论上可以在Haskell中编写不纯代码,但GC对纯代码进行了大量优化,但代价是发生了突变。例如,GHC的哈希表仍然是26日×慢于。net。从历史上看,在Haskell中,突变的性能被认为是不重要的,在GHC中编写一个指向数组的指针是5年的O(n)操作。

I investigate how to exploit multicore computation in a functional language, and target production code for some numerical applications.

我研究了如何在函数语言中开发多核计算,并针对一些数值应用程序开发目标生产代码。

The best way I have found is to learn how to write decent parallel programs for multicores in the imperative style (study Cilk, in particular) and then factor the code using first-class functions and tail call elimination into the impure functional style.

我发现的最好的方法是学习如何在命令式风格(特别是研究Cilk)中编写适合多核的并行程序,然后使用一流的函数和尾调用消除器将代码分解为不纯的函数样式。

This means cache oblivious data structures and algorithms. Nobody has ever done this in Haskell. Indeed, none of the research published on parallel Haskell to-date has even mentioned the essential concept of cache complexity. Furthermore, although it is widely known that non-strict (aka lazy) evaluation renders space consumption unpredictable, it is not yet widely appreciated that this same problem renders scalability wildly unpredictable on multicores.

这意味着缓参无关数据结构和算法。在Haskell中从来没有人这样做过。实际上,在并行Haskell到date上发表的研究中,没有一个提到缓存复杂性的基本概念。此外,尽管众所周知,非严格(即懒惰)的评估使空间消费难以预测,但人们还没有普遍认识到,这一问题在多核领域造成了难以预测的可伸缩性。

F# has Microsoft behind its back, and its parallel constructs such as PLINQ, TPL, Async Workflow have been well-documented and shown some potentials.

f#的背后有微软,它的并行结构,如PLINQ, TPL, Async工作流已经被充分的记录并且显示了一些潜力。

They are well beyond showing potential. Thousands of commercial applications are built upon those industrial-strength foundations.

它们远远超出了显示潜力的程度。成千上万的商业应用建立在这些工业基础之上。

However, research about parallelism in Haskell is very active at the moment, and it posseses many nice features which haven't supported by F# yet:

然而,关于Haskell中并行性的研究目前非常活跃,它拥有许多尚未被f#支持的好特性:

Why do you assume they are "nice features"?

为什么你认为它们是“好特性”?

I suggest reading Simon Marlow's latest paper about this:

我建议阅读西蒙·马洛的最新论文:

"...a combination of practical experience and investigation has lead us to conclude that this approach is not without drawbacks. In a nutshell, the problem is this: achieving parallelism with par requires that the programmer understand operational properties of the language that are at best implementation-defined (and at worst undefined). This makes par difficult to use, and pitfalls abound — new users have a high failure rate..."

“…结合实际经验和调查,我们得出结论,这种方法并非没有缺点。简而言之,问题是这样的:使用par实现并行性要求程序员理解最佳实现定义的语言的操作属性(在最糟糕的情况下是未定义的)。这使得使用起来很困难,而且有很多缺陷——新用户的失败率很高……

My question is which language should I choose for functional parallelism?

我的问题是,我应该选择哪种语言来实现功能并行?

I'd advise against parallel purely functional code for production because it is a complete wild card. Assuming you're happy to sacrifice some purity in order to attain competitive performance, I use and recommend F#.

我建议不要使用并行的纯函数代码,因为它是一个完整的通配符。假设你愿意牺牲一些纯度来获得竞争性能,我使用并推荐f#。

#7


6  

Haskell's purity means that it makes a clear distinction between parallel processing and concurrency.

Haskell的纯度意味着它在并行处理和并发之间有明显的区别。

  • If you are looking to speed up your big data-crunching application by distributing the work over multiple cores then you want parallel processing, which means "par" and its derivatives. By careful use of these constructs you can have your CPU-intensive pure function run N times faster on N cores whilst being sure that you haven't changed the meaning of the original code or introduced non-determinism into your program.

    如果您希望通过将工作分配到多个核心来加速您的大数据处理应用程序,那么您需要并行处理,这意味着“par”及其派生。通过仔细地使用这些结构,您可以让cpu密集型的纯函数在N个内核上运行N倍快,同时确保您没有更改原始代码的含义,或者将不确定性引入到您的程序中。

  • On the other hand if you want your program to interact with multiple entities in the outside world, interleaving communications from different entities but still having some degree of shared resources, then you want concurrency, which means using "fork" and some combination of STM and TVars. STM gives you nice transactional semantics, which goes a long way towards eliminating race conditions and other nasties of concurrency. You do need to pay attention to collision frequency and retry rates though.

    另一方面,如果您希望您的程序与外部世界中的多个实体交互,将来自不同实体的通信联系起来,但仍然拥有一定程度的共享资源,那么您需要并发性,这意味着使用“fork”和一些STM和TVars的组合。STM为您提供了良好的事务性语义,这对于消除竞争条件和其他并发性问题有很长的路要走。但是你需要注意碰撞频率和重试率。