并行科学计算软件开发语言?


18

我想从头开始开发并行科学计算软件。我想开始使用哪种语言。该程序涉及将数据读/写到txt文件中,并并行进行大量计算,并具有许多LU分解和使用稀疏线性求解器的功能。我在考虑的候选解决方案是带有OpenMP或协同阵列的Fortran 2003/2008,带有openmp cilk +或TBB的C ++,python。任何其他有文件记录的建议,我们都欢迎!我非常了解C,Fortran和Java(按此顺序)。我已经在python中完成了一些脚本编写工作,但是基本的东西。

我知道fortran很快,但是很难维护和并行化。据说C ++运行缓慢,除非您使用外部库等我喜欢的Python,但是在其上编写全面的工业级软件是否现实?

该软件需要能够处理大量数据并通过科学计算有效。性能至关重要。

对于背景,我已经有一个用Fortran编写的工作软件。许多人参与了很多年的开发,并且代码真的很脏。维护和并行化代码被证明是一场噩梦,我正在考虑其他选择。

佩特罗斯


5
作为C ++专家,我不会很难维护Fortran。可维护性在很大程度上取决于良好实践,而不是语言选择。C ++的速度太慢了。另外,我建议您增加这篇文章,以描述您的数据大小和周转时间要求。我已经看到“大的”变化幅度为9或10个数量级,具体取决于与谁交谈。
Bill Barth 2012年

@BillBarth现有Fortran代码的问题在于,涉及三个人使用不同的实践。我来自C语言背景,一个来自F77背景的人,另一个来自Matlab。无法为最大规模的系统分配和调整数据(我最近参与了)。该代码能够在350秒(经过的时间)中,在240秒的时间内对72000个微分方程和74000个代数方程进行仿真。我通过使用OpenMP并行化将其减少到170s。现在,我需要并行运行几种情况(以进行安全检查)。
ELECTRIQUE

4
@BillBarth在推销他的C ++技能方面过于谦虚,但他也过于慷慨地宣称“ C ++的缓慢性被超卖”。scicomp.stackexchange.com中有许多C ++与Fortran线程讨论了这个问题,并且总体结论是,这几乎是不对的,因为在几乎所有情况下C ++都比Fortran慢。我个人认为,今天可以将其视为都市神话。什么非常真实的是,如果你考虑到代码的可维护性帐户,然后Fortran语言今天不票价很好。
Wolfgang Bangerth 2012年

2
@BillBarth和其他人,如果您想继续讨论Fortran,C ++和其他语言的一般优点,请将其带到scicomp聊天室和@任何您想具体解决的人。
阿隆·艾玛迪亚

1
@AronAhmadia:啊,来吧,我对Jed有很多话要说;-)(Jed:另一些时间。在我们的例子中,稀疏矩阵没有STL,但是自适应网格数据结构中有很多STL。)
Wolfgang Bangerth 2012年

Answers:


19

让我尝试分解您的要求:

  • 可维护性
  • 读/写文本数据
  • LU分解的强大接口/功能
  • 稀疏线性求解器
  • 大数据的性能和可伸缩性

从该列表中,我将考虑以下语言:

C,C ++,Fortran,Python,MATLAB,Java

Julia是一种很有前途的新语言,但是社区仍在围绕着它发展,并且尚未在任何主要的新代码中进行部署。

读/写文本数据

在任何编程语言中,这都很容易实现。确保适当地缓冲和合并了I / O访问权限,并且可以从应考虑的任何一种语言中获得良好的性能。除非您知道如何高效地使用它们,否则请避免使用C ++中的流对象。

LU分解的强大接口/功能

如果要执行密集的LU分解,则需要将LAPACK或ScaLAPACK / Elemental用于并行功能。LAPACK和ScaLAPACK用Fortran编写,Elemental用C ++编写。所有这三个库都是高性能的,得到了​​良好的支持和记录。您可以使用任何您应该考虑的语言来与它们交互。

稀疏线性求解器

首要的免费提供的稀疏线性求解器几乎都可以通过PETSc(用C编写)来获得,该文件已得到充分的文档记录和支持。您可以使用您应该考虑的任何语言来连接PETSc。

大数据的性能和可伸缩性

您提到的唯一并行编程范例是基于共享内存的,这意味着您没有考虑基于MPI(消息传递)的分布式内存计算方法。以我的经验,使用分布式内存解决方案编写可扩展到超过十二个内核的代码要容易得多。如今,几乎所有的大学“集群”都是基于MPI的,大型共享内存计算机非常昂贵,因此也很少见。您应该为您的方法考虑MPI,但是无论您选择哪种编程范例,我的建议都将适用。

关于节点性能,如果您自己编写数值例程,则最容易在Fortran中获得良好的串行性能。如果您有一点C,C ++或Python的经验,那么您将获得非常可比的性能(即使使用Fortran,C和C ++也会死机,即使花费很多精力,Python和MATLAB的时间开销也只有大约25%)。MATLAB通过JIT编译器和非常好的线性代数表示性来实现这一点。您可能需要使用Cython,numpy,numexpr或嵌入式数字内核,才能从Python获得所需的性能。我不能评论Java的性能,因为我不太了解Java语言,但是我怀疑如果由专家编写,它与Python的语言相距不远。

接口说明

我希望我已经说服了您,您将能够使用所考虑的任何编程语言来完成所需的一切。如果您使用Java,则C接口将面临一些挑战。Python通过ctypes,Cython和f2py具有出色的C和Fortran接口支持。LAPACK已经被包装并且可以通过scipy获得。MATLAB在其本机库中具有您需要的所有功能,但不易于扩展或特别容易在集群上运行。Java可以通过JNI支持C和Fortran接口,但是在科学计算的集群和并行软件中并不常见。

可维护性

其中很多将取决于个人风格,但是关于可维护性的普遍共识是,您希望最大程度地减少软件中的代码行数,使用定义明确的接口编写模块化代码,并为计算软件提供测试,以验证实现的正确性和功能。

建议

个人对Python感到很幸运,我建议将其用于许多计算项目。我认为您应该为您的项目认真考虑。Python和MATLAB可能是可用于科学计算的语言中最具表现力的语言。您可以轻松地将Python与任何其他编程语言进行接口,可以使用f2py封装当前的Fortran实现,并在验证您正在维护功能的同时逐个重写Python中所需的任何部分。目前,我建议将python 2.7官方实现scipy结合使用。您可以从免费的Enthought Python发行版非常容易地开始使用此堆栈

您也可以在C,C ++或Fortran中完成大多数操作。对于具有丰富经验的专业开发人员而言,C和C ++是非常吸引人的语言,但经常使新开发人员感到困惑,因此从某种意义上来说,对于更具学术性的代码而言,这可能不是一个好主意。Fortran和MATLAB在学术计算中很流行,但是在Python提供的高级数据结构和表达能力上却很薄弱(例如,想想Python dict对象)。

相关问题:


1
一个有据可查的,全包的答案。在Fortran下,我使用了很多Lapack。我将看一下python,并尝试包装我的Fortran代码以开始并慢慢地逐步使用Python。唯一令我恐惧的是我可能有25%的时间开销。但是,如果它具有更具表现力的代码和更好的并行计算处理的好处,我会继续努力。我之所以提到共享内存只是因为该软件当前在Windows和Linux下在Uni的研究人员的2、4、8、24、48核共享内存计算机上以交互方式运行(更改数据并重新运行)。
ELECTRIQUE

3
我不知道如何用Python编写的数字内核要求25%的开销。纯Python数值内核通常比C慢100倍。Numpy和numexpr可以对某些表达式做得不错,但这几乎没有用Python编写新的数值内核。Cython可以使某些事情变得很快,但通常不会超过C的25%。Python是一种很好的“胶水”语言,但是我认为Aron过度销售它作为对性能敏感的任务的通用解决方案。
杰德·布朗

I / O是Fortran的弱点,因为Fortran在I / O中需要很多结构。我与实验室中与Cython工作的同事交谈的二手经验与Jed关于Cython所说的相吻合。至少其中一位编写了手动调整的C来代替Cython来执行性能密集型任务,然后我相信Python调用生成的C代码的性能更接近Aron的主张。另外,如果您要提及PETSc和Python,则不妨提及petsc4py。上一次我看到(这是几年前),没有针对Java的良好MPI接口。改变了吗?
Geoff Oxberry 2012年

@GeoffOxberry:Java MPI绑定存在,但近十年来没有更新。我认为他们的地位令人怀疑。Fortran具有众多的I / O选项,可以使其快速运行。我建议您探索并行HDF5(通常是HDF5)。如果I / O真正占主导地位(超过50%的运行时间),则可能需要采取更严格的措施,但是否则,类似HDF的接口的质量和可移植性值得。
Bill Barth 2012年

@BillBarth:我得检查一下。我对Fortran I / O的评论来自曾经有人建议我在Fortran中编写输入文件解析器的观点。可以通过强制执行大量结构来实现,但是我只是没有看到Fortran中容易且广泛使用的regex解析器或XML解析器库(给出一些示例)。这样做有充分的理由:我们是唯一使用Fortran的人。也许我们正在考虑不同的用例。
Geoff Oxberry 2012年

2

除了Aron的非常全面的答案之外,我还将介绍scicomp.stackexchange上的各种线程,这些线程处理采用哪种编程语言的问题-涉及程序的速度以及是否容易或困难的问题就是用这些语言编写和维护软件。

也就是说,除了在那里写的以外,让我观察一下:

(i)您在列表中加入了Fortran阵列。据我所知,实际上支持它的编译器数量非常少-实际上,我为零。最广泛使用的Fortran编译器是GNU gfortran,尽管当前的开发资源会解析一部分协数组,但我认为它实际上不支持任何一个(即,它接受语法但不实现任何语义)。 。当然,这是对较新的Fortran标准的总体观察:几年来衡量了编译器实际支持新标准的滞后时间-编译器在过去几年中仅完全实现了Fortran 2003,而仅部分支持Fortran 2008。如果您的编译器恰好支持您使用的功能,那么这不会阻止您使用其中的任何一种功能,

(ii)对于C ++ / Cilk +,当然也是如此:是的,英特尔正在GCC的一个分支上进行开发,但是它在所有GCC版本中均不可用,并且可能不会有一段时间了。您可能至少还要花2-3年的时间,直到找到典型Linux机器上安装了GCC版本的Cilk +。

(iii)C ++ / TBB是另一回事:TBB已经存在了一段时间,界面非常稳定,并且可以与过去几年中存在的大多数C ++编译器(在Linux和Windows上)一起编译。 。我们已经在Deal.II中使用它了好几年了。还有一本很好的书。

(iv)我对OpenMP有自己的见解,即它是解决问题的一种解决方案。它非常适合并行化内部循环,如果您有非常规则的数据结构,则可能会感兴趣。但是,如果需要并行处理某事,这几乎不是您想要做的-因为您真正想要做的是并行化外部循环。为此,诸如TBB之类解决方案是更好的解决方案,因为它们使用编程语言的机制,而不是尝试描述外部发生的事情(通过#pragmas)语言,并且这种方式使您无法访问线程句柄,结果状态指示器等,可以从您的程序中获取。

(v)如果您是实验性的,您可能还会看看专为并行编程设计的新编程语言,尤其是针对您所描述的任务的编程语言。我基本上要看两个: X10Chapel。我在Chapel上看到了不错的教程,而且看起来设计得很好,尽管今天当然两者都是孤立的解决方案。


作为记录,英特尔声称在其当前的编译器中内置了并行化(分布式内存)协同阵列Fortran。我们正在TACC进行调查,但我没有任何报告。Cray在其编译器中也有一个实现,但这仅在全球范围内的一小部分计算机上可用。我认为还没有人针对协同数组实现完整的Fortran 2008标准,但是在少数编译器中提供了不只是新生的支持。当然,Cilk +也可以与Intel编译器一起使用,但是依靠它可能还不明智。
Bill Barth 2012年

Fortran 2008标准直到2010年底才获得批准,因此距离CAF广泛使用还需要几年的时间。G95实际上有一个(非免费的)实现,但是不再开发了(开发者加入了PathScale)。
stali 2012年

大多数g95最终都以gfortran结尾,但CAF可能不是其中的一部分。
Wolfgang Bangerth 2012年

我相信英特尔编译器可以很好地支持协同阵列。他们使用mpiexec构建了它。这不是我的第一选择。令人高兴的是,相同的实现可以在共享和分布式内存上运行(我进行了一些测试)。随着opteron共享内存处理器以非常合理的价格达到60核,我想首先看到我的共享内存选项。
ELECTRIQUE

2

通常,如果您真的对这个软件项目很认真,我建议您以自己最喜欢的任何一种语言完全重写。听起来您将独自完成工作,因此您将以自己最熟悉的语言获得最佳效果。

不过,更具体地说,关于并行性,我鼓励您尝试一些超越常规的想法。OpenMP有其优势,但始终坚持采用顺序代码和随处并行的思想。本质上,英特尔的TBB也是如此。

Cilk绝对是朝着正确方向迈出的一步,也就是说,它迫使您在本质上并行的设置中重新考虑您的问题/解决方案。不过,我不喜欢它的另一种语言。同样,由于它只能粗略地推断出并行任务之间的关系,因此调度程序可能会非常保守,可能无法很好地扩展某些问题。

不过,好消息是,如果您对实现很认真,则可以执行Cilk的操作,例如,将问题重新编写为一组相互依赖的任务,并将其分配给多个处理器/核心,全部使用pthread或滥用OpenMP生成进程。PLASMA库中使用的QUARK调度程序就是一个很好的例子。这里给出了其性能与Cilk的良好比较。


我将查看建议的链接。比较纸非常好!谢谢!我一直在考虑pthreads,但我希望程序可以跨平台。据我所知,pthread在Windows下有问题(错吗?)。
ELECTRIQUE

@ p3tris:pthreads中的“ p”用于POSIX,因此它具有尽可能的可移植性。pthreads-win32cygwin项目中或项目中有一些兼容的Windows实现。
Pedro 2012年

基于stackoverflow.com/q/2797690/801468,我看到需要整理很多东西才能使用它。鉴于我不是程序员,所以我宁愿坚持使用经过更多测试的工具。
ELECTRIQUE

2

上面的评论中对coarray fortran的讨论很少。目前,据我所知,编译器对协同数组的支持大致如下:

  • Cray的编译器至少支持基本的协同数组功能。我已经用它编写了旨在“教育”的代码,但是我想说您可以在coarray fortran中编写真实的代码。语法和概念通常比MPI简单得多,但与往常一样,存在很多陷阱,并且陷阱与MPI不同。
  • 英特尔®fortran在其MPI库的基础上提供了对阵列的支持。据说这限制了它们的理论峰值性能,但是我还没有看到任何指标。
  • Gfortran支持协同数组,但仅适用于单个图像(或MPI中的单个等级)。因此,直到出现gfortran 4.8或4.9之前,没有真正的并行化可用。

通常,如果启动基于coarray的代码,我会小心。语法很简单,比带有MPI的Fortran / C / C ++方便得多,但是,它的功能并不那么完整。例如,MPI支持许多归约运算等,这可能对您非常方便。这实际上取决于您是否需要大量沟通。如果您想举个例子,请让我知道,如果我可以挖掘这些文件,可以给您提供一些例子。


是的,有关coarray Fortran准备好解决此类问题的更多信息肯定会有所帮助。欢迎来到scicomp!
阿隆·艾玛迪亚 Aron Ahmadia)

1

看看Spark,它是一个利用函数式编程在内存中进行计算的分布式框架。与MPI相比,Spark中的程序结构有很大不同,基本上,您编写的代码类似于单台计算机,它会作为函数自动分配给位于内存中的数据。它支持Scala,Java和Python。

Logistic回归(标量):

//load data to distributed memory
val points = spark.textFile(...).map(parsePoint).cache()
var w = Vector.random(D) // current separating plane
for (i <- 1 to ITERATIONS) {
  val gradient = points.map(p =>
    (1 / (1 + exp(-p.y*(w dot p.x))) - 1) * p.y * p.x
  ).reduce(_ + _)
  w -= gradient
}
println("Final separating plane: " + w)

有一个扩展名为 MLib(机器学习库),它使用Fortran库进行一些低级计算(对于Python,我猜是使用numpy的)。因此,这个想法很简单,专注于您的算法,而将优化置于较低级别(处理顺序,数据分发等)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.