责编 | 胡巍巍
当前最炙手可热的领域非“人工智能”(artificial intelligence)莫属。其实,“人工智能”的火热并非一蹴而就,早在1956年“人工智能”概念就已经被提出了。
那年,在美国东部的达特茅斯学院举办了历史上第一次人工智能研讨会,会上john mccarthy首次提出了“人工智能”术语,它指的是像人类那样思考的机器,这被认为是“人工智能”诞生的标志。
经过60多年的发展和探索,“人工智能”已经迎来了第三次革命——机器学习。
在互联网、大数据等前沿技术的支持下,近几年无论是人脸识别、语音识别、机器翻译、视频监控,还是交通规划、无人驾驶、智能陪伴、舆情监控、智慧农业等,“人工智能”正在不断取得突破性的进展。
未来是“人工智能”的时代,它会日益渗透到各行各业、各个领域的方方面面之中,如何将“人工智能”恰到好处地发挥作用,主要体现在软件程序的开发上。
本质上,软件程序是由编程语言开发实现的,选择合适的编程语言不仅可以提高软件的开发效率,也可以提高软件的使用质量,它是软件开发过程中的关键环节。
当前的编程语言种类繁多,琳琅满目,我们需要对编程语言有更全面的了解才能得心应手的选择最适合的一种。那么,它们的核心区别是什么?
又是如何一步一步发展出来的?哪种编程语言是“人工智能”领域的最佳选择?本文就以“人工智能”的编程语言发展历史为轨迹,给出这些问题的答案。
初识编程语言
如果说语言是人与人之间传递信息的纽带, 那么编程语言则是把人的思维传递给计算机的纽带。计算机执行的每一个步骤,都是以编程语言所编写的程序来执行的。
目前的编程语言有c、c++、c#、python、java、php、go、javascript等,虽然每种编程语言的语法不同,但是它们最终的目的是为了让计算机工作。
另一方面,cpu芯片只能识别机器指令,因此,尽管不同的编程语言在语法上差别很大,最终还是被转换为cpu芯片可以执行的机器指令。
比如c、c++这些编译型的编程语言只有经过编译工具的处理后才能被cpu芯片所识别。
举个例子说明这个过程。我们在linux平台上用c语言编写完程序,接下来需要用编译工具处理这份程序文件,我们选择一款常用的编译工具gcc(gnu compiler collection),然后使用gcc的命令语法分别完成预处理、编译、汇编、链接这4个阶段,最后会生成一个可执行二进制文件,这个文件就是由机器指令所组成的。对于那些编译型语言的集成开发软件而言,它们为了提高开发效率把编译过程封装成了控件操作,在编译原理上仍然是相同的。
python这类解释型语言与编译型语言则有所不同。由python语言编写完成的程序文件无需编译为可执行二进制文件后再执行,而是可以调用python解释器逐一将程序语句解释成可执行的机器指令。
使用者无需关心程序的预处理、编译、汇编、链接这些过程,这使得开发工作变得更加轻松,不过在程序执行时所增加的解释过程也使得它比编译性语言在执行效率上有所劣势。
至于为什么python能够用动态解释的方式执行程序,关键点在于python解释器上。python解释器根据实现的语言不同分为不同的版本,比如java版的jython,.net版的ironpython等,源生的python解释器是基于c语言实现的,称为cpython。
当我们从python官网下载并安装好python 后,我们会得到一个cpython解释器。运行python程序文件时会启动cpython解释器,解释器首先将程序文件(.py)编译为字节码(.pyc),然后再将字节码转换为可执行的机器码。
编程语言的发展
市面上虽然有形形色色的编程语言,但是从理论上来讲,每种编程语言几乎可以实现同样的功能,它们的产生是为了迎合不同应用场景的发展需求罢了。
总体来说,编程语言的发展历史可分为三个阶段,第一阶段的机器语言、第二阶段的汇编语言、第三阶段的高级语言,这是一个逐步进化的过程。
机器语言是第一代编程语言,它指的是用二进制的0/1指令集来表示的语言,也是计算机唯一能够识别的语言。
指令的基本格式由操作码和操作数两部分组成,操作码指明了指令的操作功能,操作数表示该指令的操作对象。早在1946年,世界上诞生了第一台计算机,当时的程序员只能通过机器语言来编写程序。
他们采用的方法是,先在卡片上用穿孔方式表示0/1指令集,再用读卡机读取卡片上的程序并加载给计算机去执行。
机器语言是直接面向计算机cpu操作的语言,因此执行效率很高,但是大量繁杂琐碎的细节牵制着程序员,编写难度高、可读性差、不便于移植等缺陷,使得他们不得不把时间和精力专注在如何确保程序的正确性上。机器语言太过于晦涩难懂,于是推动诞生了汇编语言。
汇编语言是第二代编程语言,也称为符号语言,它用助记符代替了操作码,用地址符号或标号代替地址码,比如mov r0,#0x100表示的含义是把0x100赋值给r0,这样相对来说更加容易理解和记忆。
当然,汇编语言的符号可以被人类接受,但并不能被计算机识别,对此还要通过一种软件将汇编语言的符号转换为机器指令,这个软件就是编译器。
由于不同的cpu会有不同的指令集,因此每种cpu的厂家都会提供自己专属的汇编语言语法规则和编译器,在编译器中记录着汇编语言各种符号与机器指令之间的对应关系。
这样一来程序员可以用汇编语言编写程序,然后通过编译器把汇编语言编译成机器指令。
相比与机器语言,汇编语言在可用性上已经有很大的进步了,但是它仍然是面向机器的一种低级语言,虽然执行速度快、效率高、程序体积小,但是编写和调试上的复杂性仍然促使着编程语言向更高级的语言去进化。
高级语言是第三代编程语言,当编程语言发展到这个阶段时,已经从面向机器进入到面向人类的层面。
程序员可以不依赖于特定型号的计算机,使用接近于自然语言、数学公式这些更容易理解的方式编写程序,并且编写的程序能移植到各种平台上正常运行。
高级语言的发展也分为两个阶段,分别为前一阶段的结构化语言或者称面向过程语言,后一阶段的面向对象语言。面向过程语言的典型代表有c、 fortran、cobol、pascal、ada等等,面向对象语言的典型代表有java、c++、c#、python等。
简单的说,面向过程和面向对象是两种编程的思想。面向过程是建立在“过程”概念上来指导软件编程的思想,比如在学习和工作中,当我们去完成某项任务时,会罗列出完成这件事情的若干个步骤,假如其中某一步骤特别复杂时,又可以将它细化为若干个子步骤,以此类推,直到问题解决。
实质上这些步骤就是“过程”,按照步骤去解决问题的思想就是面向过程的思想。基于面向过程“自顶向下、逐步求精”的编程思想才有了“高内聚,低耦合”模块化编程的要求。
面向对象是建立在“对象”概念上来指导软件编程的思想,认为客观世界由各种对象组成,任何事物都是对象。比如把“程序员使用电脑”这个事件对象化,首先用抽象的方式建立“人”和“电脑”两个类,类中分别包括所有的属性和函数,再以继承“人”类的方式派生出一个“程序员”类,把“电脑”类以组合的方式作为“程序员”类的属性,在“程序员”类中添加“使用电脑”函数,最后实例化一个名为tom的程序员和一台dell电脑,tom实例调用了“使用电脑”这个方法。
以上对比可以看出,当程序简单、规模较小的场景下,面向过程编程使得程序流程更加清晰,但是当面对复杂程序时,面向对象易维护、易复用、易扩展的优点就体现了淋漓尽致了。
可见从面向过程语言到面向对象语言的发展可以看出,随着时代的发展,编程语言需要解决的问题越来越复杂,编写的程序规模也越来越庞大,软件的开发、程序的维护、功能的修改变得越来越频繁。
因此,面向对象语言是当前计算机技术发展到一定阶段的产物,从面向过程过渡到面向对象的编程方法也是大势所趋。
目前面向过程语言中fortran、basic 和 pascal 这些语言基本上已经很少有人使用了,而c语言仍然是计算机领域最重要的一门语言,特别是在系统编程、嵌入式编程领域占据着统治地位。
c语言的起源与unix的改进是密不可分的。在1969至1970 年期间,美国电话电报公司(at&t)贝尔实验室的ken thompson和dennis ritchie等人使用汇编语言编写了第一个版本的 unix 操作系统。
由于unix 操作系统良好的性能,在其发布初期,就迅速得到了推广和应用。不过汇编语言依赖于计算机硬件,在可读性和可移植性方面都比较差。
1973 年,ken thompson和dennis ritchie在做系统内核移植开发时,发现使用汇编语言很难实现,他们需要一种集高级语言和汇编语言的优点于一身的编程语言来编写unix内核。
于是在先后使用了bcpl语言、b语言之后,由dennis ritchie设计出了c 语言,成功地重新编写了 unix内核。
不过c语言并不是从0到1开发出来的,它的原型可追溯到1960年出现的algol 60语言,也称为a语言。
由于algol 60语言离硬件层面比较远,不宜用来编写系统程序,1963年英国剑桥大学在algol 60语言的基础上推出了更接近硬件编程的cpl(combined programming language)语言。
1967年英国剑桥大学的martin richards又对cpl语言进行了简化,推出了bcpl(basic combined programming language)语言。之后的发展历史则对接到了上文提到的贝尔实验室unix内核开发。
1970年ken thompson以bcpl语言为基础作出进一步简化,推出了b语言用于编写unix内核。不过b语言过于简单、功能有限,在1972年至1973年期间dennis ritchie在b语言的基础上设计出了c语言。后来c语言的改进也主要用于贝尔实验室内部,直到1975年unix第6版公布后,c语言的突出优点才引起人们普遍关注。
在1977年为了使unix操作系统推广到其他机器上使用,dennis ritchie发表了c语言编译文本《可移植的c语言编译程序》,这使得c语言在其它机器上的移植工作大大简化。可见c语言和unix是相辅相成地发展着的,随着unix的日益广泛使用,c语言也迅速得到推广。
1978年,dennis ritchie和brian kernighan出版了《the c programming language》(《c程序设计语言》),这本书影响深远,被c语言开发者作为c语言的非正式的标准说明,也称为“k&r”(作者名称首字母结合),这个版本的c语言称为“k&r c”。
从此之后c语言开始风靡全世界,它被广泛应用在大型主机到小型微机的各种场合,由于‘k&r’中并没有定义一个完整的标准c语言,于是同时期衍生出了很多不同版本的c语言。
为了统一这些c语言版本,在1983年美国国家标准局(american national standards institute,简称ansi)成立了一个制定c语言标准的委员会,根据c语言问世以来各种版本对c的发展和扩充制定了新的标准——ansi c。1988年,dennis ritchie和brian kernighan修改了经典著作《the c programming language》,在第二版中涵盖了ansi c语言标准。
1989年ansi c语言标准被正式批准,称为ansi x3.159-1989 programming languages - c,由于这个版本是 89 年完成制定的,因此通常被称为 c89。
之后ansi 又把ansi c标准提交到 iso(国际化标准组织),1990年被 iso 采纳为国际标准,称为 iso c,又因为这个版本是1990年发布的,因此也被称为c90。
ansi c(c89) 与 iso c(c90)在内容上基本相同,虽然后来c语言也有一些修改,但目前广泛使用的c语言版本仍然是 ansi / iso c。
c语言的影响力不仅于此, c++、java、c#、python等编程语言也是以c语言为基础发展起来的。
这也是为什么大学里将c语言作为计算机教学的入门语言的原因,因为掌握了c语言,再学其它编程语言,能够触类旁通,很快就能上手。
比如c++编程语言是1979年bjarne stroustrup从c语言的基础上扩充而产生的,最开始引入了类的概念,称为“c with class” 语言。在1983年,“c with classes”语言才更名为c++,“++”符号也表明了是对c语言功能的递增。
c++从正式更名一直到1985年商业版本正式问世,这个时期又加入了虚函数、函数重载、引用机制等许多重要的特性。
1989年,c++再次版本更新,这次更新引入了多重继承、保护成员以及静态成员等语言特性。之后每隔几年c++都会从易用性、安全性等方面进行版本的升级。
所以说万物的发展都离不开吸收和借鉴,同样java也不例外。在1991年,sun公司的开发小组在使用c++语言时发现它十分繁琐,于是应运而生了java语言。
java在发展的过程中吸收了c++很多优点,同时也摒弃了c++里面多继承和指针等复杂的语法,增加了垃圾回收器等功能。
经过这些年的发展, java的功能也变得越来越强大。c# 则是微软公司看到 java 很流行,在2003年所发布的一个与 java 语法相似的语言。
从以上编程语言的发展历程可知,不同编程语言它们都拥有各自的应用场景,它们的产生本质上就是为了帮助程序员能够更好地解决问题。
最适合ai的语言
对于“人工智能”来说,选择不同的编程语言实质了决定了“人工智能”的期望程度,因此这也是目前争论的焦点——哪种编程语言是“人工智能”领域的最佳选择?
最近几年,随着人工智能概念的火爆,python语言迅速升温,成为众多ai开发者的首选语言。
python的诞生在1989年,最初并不是为了契合ai的发展,而是荷兰人guido van rossum为了打发圣诞节假期开发了python语言的解释器。
python这个名字,来自guido所挚爱的电视剧monty python’s flying circus。
他希望python语言,能符合他的理想:创造一种c和shell之间,功能全面,易学易用,可拓展的语言。
python语言适合于ai的优点,除了语法简单、使用方便、快速上手之外,更重要的是拥有强大的第三方库的扩展,其中就包括了许多数据分析、机器学习方面的第三方库。
比如python数值计算最重要的基础库——numpy,大多数提供科学计算的库都是用numpy数组作为构建基础,如pandas库、scipy库等。
numpy中主要以n维数组对象ndarray存储数据的,ndarray作为numpy的核心,不仅具有矢量算术运算的能力,并且在处理多维的大规模数组时快速且节省空间。
在处理矩阵的转置、求逆、求和、叉乘、点乘等运算时,只需用一行简单的表达式代码就能代替for循环。
在运行效率上,得益于底层c语言编写的算法机制,numpy会比纯python快几个数量级,几乎接近与编译过的等效c语言程序的处理速度。
pandas则是python环境下最有名、最专业的数据分析库,虽然numpy提供了通用的数据处理的计算基础,但在处理表格数据时大多数使用者仍然将pandas作为统计和分析工作的主要工具,pandas使得python中的处理数据变得非常方便、快速和简单。
在机器学习的可视化方面有高质量的绘图库——matplotlib库,它具有很高的灵活性和集成能力。再比如scipy库可以轻松处理包括线性代数、微积分、信号处理等各种数学运算。
scikit-learn库是建立在scipy,numpy和matplotlib之上的机器学习框架库,提供了机器学习中回归、分类、聚类、数据降维等各种成熟、通用的分析方法。
还有由google brain团队开发的tensorflow库可用于神经网络等深度学习模型的研究……这些库使得python在ai领域的具有很强的竞争力。
python也并不是没有缺点,作为一门解释性语言,最明显的缺点就是执行速度的局限性,这会导致在处理某些高频任务时存在瓶颈。
幸好python本身由c语言实现的,在设计之初考虑到了通过足够抽象的机制让c/c++之类的编译型的语言能够导入到python脚本程序中。
这样的话,在开发性能要求较高的程序模块可以通过扩展运行效率更高的c/c++语言来弥补自身的弱点。
另外有些算法已经有开源的c/c++库,那么也没必要用python重写一份,只需要用python 的ctypes 库或者python源生代码扩展方式调用这些库即可。
当然,除了python之外,c ++、java、r、prolog、lisp这些语言也是不错的选择之一。c++提供更快的执行和响应时间,普遍应用在搜索引擎、游戏等领域的开发。
java不仅能够适用于机器学习相关搜索算法、自然语言处理算法、神经网络算法,更大的优势是易于使用、调试,简化了大型项目的工作。
r语言和python一样拥有强大的第三方库,有接近10,000个数据科学和分析相关的第三方库的支持,在统计分析和机器学习算法的实现上非常有优势。
lisp和prolog都属于非常古老的编程语言,不过随着时间的推移,它们已经是ai项目开发的常用语言。
prolog拥有强大而灵活的编程框架,lisp则为开发人员提供了足够的自由,它的灵活性可以快速进行原型设计和实验。
总结
人工智能是一个非常广阔的领域,不同的领域的应用场景对编程语言的特性要求也不尽相同,因此选择合适的编程语言非常重要,不仅能够为开发人员节省时间及精力,也能增加系统的稳定性。对于开发人员来说更是要站在全局的视角去审视编程语言的选择。
作者介绍:元宵大师,python高级工程师,致力于推动人工智能、大数据分析在金融量化交易领域中的应用。欢迎大家关注我的个人公众号《元宵大师带你用python量化交易》。
【end】