理论化学编程中的Fortran与C++之争

来源:emuch.net/html/201111/3885537.html


理论化学编程中的Fortran与C++之争
自从有了程序设计语言,“哪种编程语言好”就成为了亘古不变的话题。这个问题一经提出,必然会招来一场巨大的口水仗。作者曾经在一些论坛上提出了类似 “Fortran和C++那个用的多”之类的问题,回帖全部达几十个以上,各种意见针锋相对,犹如Fortran和C++信徒之间的“圣战”一般好看。
有很多人曾经请C++语言之父Bjarne Stroustrup做一个C++与其它编程语言的比较,而Stroustrup明确的拒绝了。他指出,从技术上讲,一个所谓的“公平”的比较将会涉及到 大量的技术,这是一个工作量巨大的任务,绝对不是简单的用C++和其它语言写同一段代码然后比较其运行时间就能完成的。这种比较涉及到具体的应用领域和用 户需求,所处理的信息类型,编译器的质量(不同语言的编译器开发的投入是有相当大差别的),程序员的水平与“偏好”,编程语言的标准(如究竟是C++97 与Fortran90比较,还是应该C++0x与Fortran2003比较?)等等。他甚至认为,这种比较是“rarely meaningful”的。
因此,今天作者也不打算为某种编程语言摇旗呐喊,而是仅就科学计算编程领域,特别是,限于作者专业即量子化学和分子模拟,来谈一谈两大“主流”编程语言:Fortran和C++的在理论化学界的应用历史,以及某些人(包括作者)对它们的看法。
1 Fortran的美好时代
毋庸置疑,1957年出现的Fortran是世界上第一个高级编程语言。它的出现,大大降低了普通科研人员学习编程的门槛,而且增强了代码的可移植性。在 此之前,人们都是用机器语言直接书写程序,这种语言对于一般人而言难度太大了,而且是与运行机器相关,因此很难写出高效且具有可移植性的程序。
例如,Roothaan在研究原子自洽场的计算时专门为IBM 7030数字计算机写了一些程序,这些程序用来优化Slater基组已经10多年了。不幸的是,由于该程序是完全使用IBM的机器语言所书写,因此在20 世纪60年代,当这种机器逐渐消失时,这些程序逐渐成为了废品。意识到这个资源的重要性,Clementi及其同事决定把这些程序用Fortran全部重 写,并且增加了处理Gauss基组的功能。这段代码从此复活,成为了量子化学程序库中一个重要部分。
Fortran语言的重要性从此被理论化学家所知。它的优点几乎数不胜数。首先,它的语法简单,任何一个理论化学的研究生几乎一天就能学会,可以迅速用它 开展工作;其次,它的运行效率极高,不要说现代编译器(如GNU Fortran或intel Fortran编译器),就是世界上第一个Fortran编译器都可以将其每一语句都翻译成几乎没有冗余的、效率至少不低于手写的机器码;第 三,Fortran代码具有可移植性,与机器无关。很快,在20世纪60~80年代,一批批量子化学程序如雨后春笋般出现,如早期的 Gaussian,Polyatom,以及后来的GAMESS,NWChem等等,几乎全部都是由Fortran77编写的。Fortran77在量子化 学领域绝对是功不可没,它为普及和发展量子化学做出了巨大的贡献。那个时代,Fortran77是很多自然科学研究生的必修课。
自此,Fortran成为了数值计算领域的“主流”语言。
2 C语言的崛起
20实际70年代,C语言逐渐崛起。这个语言是为了编写Unix操作系统而开发的。很快,这种“半汇编”性质的高级语言,由于其具有极其灵活的控制机器的 能力而深受计算机专业人士的喜爱。不过,由于其学习难度较之Fortran稍高,而量子化学以纯粹数值计算为主,Fortran足以满足要求,因此C在量 子化学领域没有什么明显优势,因此大多数量子化学家对其不感兴趣。此时,C和Fortran处于“井水不犯河水”的状态。
而80年代左右,分子模拟科学开始发展。由于分子模拟的流程相对复杂,Fortran77语言在实现某些功能时稍显繁琐,如对某些配置文件进行语法分析, 一些模式识别和人工智能过程等等,此时C语言的优势开始显露,大量分子模拟领域的研究组开始用C开发程序,如分子对接软件Autodock等等。 Fortran垄断地位的打破,表明理论化学领域编程语言之战的种子已经悄然的埋下。
3 理论化学软件开发的瓶颈
在任何软件开发领域(学术界还是商业界),前人留下的代码库都是无比宝贵的财富。因为无论程序员的水平有多高,代码毕竟是一个字一个字的敲进去的。比如矩 阵乘法这种通用的操作都需要每次重新写,那会浪费大量宝贵的人力财力。在前人的基础上开发新的功能,是大型软件开发的通用规则。量子化学自60年代以来, 积累了大量的Fortran程序库,它们的开发都是非常艰苦的,是无数量子化学家智慧的结晶,每个研究组都要在前人的基础上继续的研究,例如现在的 Gaussian09里面还使用着当年Pople亲手敲进去的代码。
不幸的是,到了90年代,这种长期的积累,既是这个组的财富,同时却也是软件继续发展的一个致命的阻碍。这些开发于60年代的量子化学程序,几乎都是“无 组织无纪律”的开发的,根本没有料到后来的发展程度。因此,很多组逐年积累达万行的程序,几乎毫无任何代码美感可言:变量命名难以理解(我见过一个 Ewald求和程序里面充斥着p,pp,ppp这样的变量名),逻辑结构杂乱无章(goto,if之类随意嵌套)。维护人员在阅读以前的源码时需要消耗大 量的精力,而这是一个痛苦的过程。早期的量子化学程序都有大量的common块,而每个subroutine有大量的参数传递(有个软件的 subroutine居然有100多个参数!!)。阅读这种代码简直让人崩溃!
插个笑话,这是一段Fortran代码的注释:
C 1967-Nov-11  Only the God and I know what it intends to do.
C 1967-Nov-13  Only the God knows what it intends to do.
而最大的问题是,由于程序最初的设计没有任何软件工程的考虑,要继续开发和改进这种没有封装和可扩展性的代码将会变得异常困难。举一个例子。开发相对论量 子化学软件DIRAC时涉及到了一个四元矩阵,这种四元矩阵有两种存储方式:A(N, N, 4)和A(4, N, N)。由于某些历史原因,最初的设计采用了A(N, N, 4)。现在,由于内存硬件的改变,A(N, N, 4)的乘法操作比A(4, N, N)要慢4倍。但是,由于最初设计的缺陷,几乎所有的subroutine都是显式的处理A的各个下标,因此,若要改进A的存储方式几乎要对所有的代码进 行大手术,这简直就是不可能的任务。因此,直到现在(2011),DIRAC还在忍受着这种四倍的性能惩罚!这是不重视软件工程的一个惨痛教训。
由于学术领域的特性,一个组常常是“铁打的营盘流水的兵”,一个学生参与软件开发往往最多四五年就会离开,新来的学生要从头学起。由于学生基本不具有软件 工程的背景,而写代码水平又参差不齐,导致不同时期加入程序的代码,不论风格还是性能都相差甚远,这种差异更使得软件的发展走向死胡同。
Fortran的结构化特性是把双刃剑。它使得程序开发的入门变得非常容易,但又使长期维护变得异常困难。特别是代码达到万行级别以上时候,后续开发者的工作量越来越大。此时,软件开发者逐渐开始反思过去的教训。新的概念:封装,多态,面向对象开始走入他们的视野。
4后起之秀:C++
C++作为一种混血语言,兼具面向过程和面向对象的特性,很快稳坐了大型商业软件开发语言的霸主地位(Not mention Java here)。但是,不知为什么,理论化学界的会Fortran的人往往对C++有一种说不清楚的“敌视”的态度。也许是一种情节吧,毕竟用Fortran 人们开发了很多经典的程序,就像Visual C++出现之初,很多人还在恋恋不舍的使用着Turbo C++,因为Turbo C++开发了无数经典的软件。
在90年代末,一些理论化学研究组终于决定放弃Fortran,这个决定应该来说是很需要勇气的,因为意味着放弃前人宝贵的Fortran程序库。(注 意,这并不是说C,C++不能调用Fortran的函数或过程。但是,对于大型程序,如果这些东西不是专门设计的,混合调用会带来很多麻烦)。Frank Neese在开发ORCA(一个量子化学程序)时毅然决定使用C++,因为他认为保持代码的结构性和统一性与程序运行的性能是同等重要的。十几年过去 了,ORCA的代码已达百万行,他发现C++为保持代码的可维护性做出了重要的贡献。每一个新进入组的学生在一到两周内就可以对程序作出实质性的贡献。他 提到,新进入组的某些人确实对C++和C抱有极大的敌意,但是经过一段时间后,他们都同意“It is much more convenient to use the ORCA C++ infrastructure compared to the Fortran codes they were used to.”
不过,他也说,Fortran也可以做到这一点。但是,Fortran的面向对象特性是在Fortran90后才加入的(如module,但有人认为这简 直是个“ugly hack”),而历史上大多数量子化学程序都是Fortran77的,设计本身又没考虑软件工程这一点,因此Fortran的面向对象特性很少直接的投入 应用。
90年代中期,分子动力学软件NAMD开始开发。其设计者也决定采用C++。开发者之一Andrew Dalke称,他们选择C++的原因是为了处理复杂的空间分解数据结构和进程间通信。NAMD是目前为止软件工程做的最好的科学软件之一。直到现 在,NAMD还在维护和开发中,其性能和可扩展性在同类软件中都是一流的。
Gaussian是用Fortran77编写的,而90年代中期,从Gaussian公司中跑出来的一批人(Pople(我心中的神啊)和Head-Gordan)在编写Q-Chem时,也采用了C++ ……
5 大论战:Fortran和C++孰优孰劣
好吧,终于还是到了这个让人头痛的问题。
首先,我们还是看看性能吧。
一些软件工程专业人士说,代码的“可维护性”远比“性能”更重要。作者认为,在科学计算领域,这个说法是不合适的,至少换成“代码的可读性与性能同等重 要”,因为这些软件,一旦运行起来常常都是以天为单位,其存储读取和浮点数操作及其巨大,一个小小的性能提升可以使运行时间缩短几天,这对提高科研效率是 及其重要的。因此,这里将性能的考虑放在第一位。
大家都比较公认,Fortran和C在性能上没有实质差别,因为他们的相对底层性,每一条语句都可以比较直接的翻译成对应的机器语言。因此决定性能的因素 几乎只有算法。而C++则不同,C++为了实现多态等特性,添加了大量额外代码,这些性质可能会对性能造成损害。最为人诟病的,就是虚函数和大型对象的复 制。例如,某软件涉及到大量频繁的I/O操作(例如量子化学中分子积分的缓存文件),测试发现,使用C++标准库iostream的cout对象类要比C 的fprintf函数和Fortran的write语句要慢三倍左右。
也有人认为,这些所谓的“性能杀手”的责任不在语言,而在程序员。例如,大循环体内的虚函数会大大降低程序的性能,而这完全可以通过重新设计类的层次结构 或使用内联函数来解决(事实上有人认为在理论化学程序的设计中虚函数根本就没有必要使用);大型对象的复制可以通过预取缓存的技术来解决,或者干脆避免这 种操作。当然,这有偷换概念之嫌。除此之外,一般认为对于同样的算法,Fortran,C,C++的性能没有实质性的差异。
数值计算的经典名著Numerical Recipe,在第一版时,里面的程序都是用Fortran(也有Lisp,Pascal之类)写的,而2007年第三版时,所有的程序都改成了C++, 里面也用了模板,继承等技术,可见他们也认为C++和Fortran的性能不会有明显差别。
但是,还有一个不可忽略的因素,就是编译器!像C++这样的大众语言,新技术厂商会为其投入巨资进行研究,而Fortran这种现在小众的语言,他们的开 发受到冷落。一旦编译器的质量下降,这种语言的性能和应用也会遭到致命的打击。一个分子模拟软件MODELLER是用Fortran95写的,在编译软件 时,无论是intel还是GNU Fortran编译器都会产生各种各样的错误,开发人员不得不禁用一些优化选项来避免这些错误。另一个体现是,直到现在(2011),几乎没有哪个厂商生 产了完全支持Fortran2003标准的编译器!如果这样下去,Fortran在性能上的优势也可能逐渐消失。
下面我们看看软件工程上的考虑。
Vincent Leroux称,他确实发现“maintaining large Fortran projects may turn into a nightmare easily”,C++在清晰的表达抽象数据关系上有明显的优势。他以分子动力学软件CHARMM和NAMD为例,前者是Fortran写的,后者是 C++写的,这两者代码的清晰程度几乎有天地之别。前面提到的ORCA也是一例。因此,人们倾向于认为C++开发的程序更具有长远的生命力,更易扩展和维 护。
当然,用Fortran写出好的代码也并非不可能。一个例子是分子动力学软件TINKER,另一个就是量子化学软件GAMESS。GAMESS已逾二十余 年,它使用Fortran77编写。由于它的开发非常规范(含有程序员手册;代码写作坚持统一风格;代码注释详细等),并具有统一的DDI接口,因此 GAMESS始终得到了量子化学界的广泛拥护。直到现在,很多新的电子结构方法都借助GAMESS的平台来发展,如XMVB,XIAN CI(这两个都是国人开发的:分别由厦大的吴玮组和西北的文振翼组开发),SAPT等等。但是,这两个似乎只是特例。大多数组里Fortran的程序人们 之所以还在改进,似乎更多是出于成本的缘故。毕竟组里累计了多年的程序是舍不得扔的,而重写代码所需的工作量太巨大了,或者说,根本不会做。这一点常被人 忽略,但却很实在。比如,作者学校某个化学组至今(2011)还在使用一个用QBASIC写的磁性计算程序,这并不是因为他们对当初写这段代码的师兄怀有 感情,而是因为:现在组里根本没有人会写代码。
6 迎合新技术?
Fortran在某些方面确实有些不思进取。从77到95标准整整经历了19年,指针、动态内存分配、模块技术才姗姗来迟,而迄今类似于“析构函数”的东 西也不存在,从而使垃圾回收变得非常麻烦,这对大型程序的开发十分不利。而C++不仅天然存在这些特性,其丰富的STL可以很容易的构造高层次的数据结构 (堆栈,链表等)。在这一方面,Fortran是应当受到批评的。
尽管并行技术,如OpenMP,MPI等同时支持Fortran和C(so C++),但是这些技术都是在90年代出现的。事实上,对于大型程序的并行很多人还是提倡使用C++。C++的抽象技术可以减少节点通信模块与纯粹数值计 算模块之间的耦合,而Fortran很难做到这一点。就连以Fortran77为标准的GAMESS的数据接口程序DDI也是用C写的。前面提 到,NAMD的作者也是这么认为的。
2005年左右开始流行的CUDA加速技术大大提高了理论化学的计算效率,它只支持C。Fortran的CUDA技术还有些问题(Porland Group Fortran),不知何年才能见到正式版本。Terachem作为第一个支持GPU加速的量子化学软件,就是使用C编写的。如果Fortran不能充分 发挥新技术的威力,它的淘汰是迟早的事,尽管作者也不愿看到。
讨论了这么多,可能有读者觉得作者已经违背了开头提到的“不打算为某种编程语言摇旗呐喊”的原则,有些“贬Fortran褒C++”之嫌。也许是吧。作者 本人也是Fortran的粉丝,但是在这几年的编程中,确实感觉到在数值计算领域,Fortran已经不可能再实现垄断地位。也许,我们确实应该接受一下 新生事物,尽管C++的语法不友好(在懂Fortran的人看来),但是还是应当尝试一下。如果在实际的工作中,C++真的胜过了Fortran,那么, 我们就应该接受这个事实。毕竟科技在进步,也许过几年,我们会在地铁上拿着iPhone来运行量子化学软件。
见The Design and Evolution of C++前言
B Roos, C Slatez, A. Veillard, E Clementi. Technical Report RJ 518 (IBM Research, San Jose, Aug 12, 1968)
U. Ekström, University of Olso,通信
Frank Neese, Max-Planck Institut für Bioanorganische Chemie, Germany,通信
Andrew Dalke, Dalke Scientific,通信
Ben Webb, University of California San Francisco,通信
Vincent Leroux, Centre National De La Recherche Scientifique,通信
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章