1.2 Spark简介

Apache Spark是一个开源集群运算框架,最初由加州大学伯克利分校AMPLab开发。相对于Hadoop的MapReduce在运行完工作后将中间数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘时即在存储器内分析运算。Spark基于内存运行程序的运算速度能做到比Hadoop MapReduce的运算速度快100倍,即便基于硬盘程序时,Spark的速度也能快10倍。Spark允许用户将数据加载至集群存储器,并多次对其进行查询,非常适合用于机器学习算法。使用Spark需要搭配集群管理员和分布式存储系统。Spark支持独立模式(本地Spark集群)、Hadoop YARN或Apache Mesos的集群管理。在分布式存储方面,Spark可以和Alluxio、HDFS、Cassandra、OpenStack Swift和Amazon S3等系统通过接口程序集成。Spark也支持伪分布式本地模式部署,不过,通常只用于开发或测试时以本机文件系统取代分布式存储系统。在这样的情况下,Spark可以在一台机器上使用每个CPU核心运行程序。Spark成为Apache软件基金会以及大数据众多开源项目中最活跃的项目。

另外,Apache Spark是一种快速和通用的集群计算系统,提供Java、Scala、Python和R高级语言API,还支持一系列高级工具,包括用于SQL和结构化数据处理的Spark SQL,用于机器学习的MLlib,用于图形处理的GraphX和用于数据流处理的Spark Streaming(见图1-2)。

图1-2 Spark组件

1.2.1 技术特性

在Spark的技术框架中,Spark核心是整个项目的基础,提供了分布式任务调度和基本的I/O功能,而其基础的程序抽象则称为弹性分布式数据集(RDD),是一个可以并行操作、有容错机制的数据集合,其运行机制是:通过将工作数据集缓存在内存中,进行低延迟计算,后续迭代算法通过内存共享数据,高效重复访问相同的数据集。RDD可以通过引用外部存储系统的数据集创建,例如共享文件系统、HDFS、HBase或其他Hadoop数据格式的数据源,或者是通过现有RDD的转换而创建,如map、filter、reduce、join等。对RDD进行的读写操作被抽象化并且提供了统一的接口,可以通过Scala、Java、Python和R四种语言之一进行调用,简化编程复杂性,应用程序操纵RDD的方法类似操纵本地端的数据集合。Spark的组件包括以下几种。

1.Spark SQL

在Spark核心之上,Spark SQL使用了名为SchemaRDD的数据抽象化概念,提供结构化和半结构化数据相关操作的支持。Spark SQL提供了领域特定语言,可使用Scala、Java或Python操纵SchemaRDD,支持使用命令行界面和ODBC/JDBC服务器操作SQL。在Spark 1.3版本,SchemaRDD被重命名为DataFrame。Spark SQL用于结构化数据处理,这与基本的Spark RDD API不同。有几种与Spark SQL进行交互的方式,包括SQL语句和Dataset API。Spark SQL的一个用途是执行SQL查询,也可用来从现有的Hive安装中读取数据。从另一种编程语言中运行SQL时,结果将作为数据集或数据框返回。

2.Spark Streaming

Spark Streaming充分利用Spark核心的快速调度能力运行流分析。Spark Streaming是Spark核心API的一个扩展,对即时数据串流的处理具有可扩展性、可容错性等特点,可以从kafka、flume、ZeroMQ、Kinesis等获得数据,并且可以使用复杂的算法进行处理,这些算法包括map、reduce、join和window等高级函数表示,处理后的数据可以传送到文件系统和数据库中,还可以将Spark的机器学习和图形处理算法应用于数据流。

3.MLlib

MLlib是Spark上的分布式机器学习框架。MLlib可使用许多常见的机器学习和统计算法,简化大规模机器学习时间,其中包括汇总统计、相关性、分层抽样、假设检定、随机数据生成、支持向量机、回归、线性回归、逻辑回归、决策树、朴素贝叶斯、协同过滤、K平均算法、奇异值分解(SVD)、主成分分析(PCA)、TF-IDF、Word2Vec、StandardScaler、随机梯度下降法(SGD)、L-BFGS。

4.GraphX

Spark GraphX是一个分布式图处理框架,它是基于Spark平台提供对图计算和图挖掘简洁易用的、丰富的接口,极大地方便了对分布式图处理的需求。众所周知,社交网络中人与人之间有很多关系链,如Twitter、Facebook、微博和微信等,这些都是大数据产生的地方,都需要图计算,现在的图处理基本都是分布式的图处理,并非单机处理。Spark GraphX由于底层是基于Spark处理的,所以天然就是一个分布式的图处理系统。图的分布式或者并行处理其实是把图拆分成很多子图,然后分别对这些子图进行计算,计算时可以分别迭代进行分阶段的计算,即对图进行并行计算。

Spark在其核心上提供了通用的编程模型,使开发人员可以在弹性分布式数据集上运行运算,如Map、Reduce、Join、Group和Filter等,还实现了运算的组合,使得可以表达更复杂的数据操作,如迭代机器学习、流式传输、复杂查询和批处理。此外,Spark跟踪每个操作生成的数据和过程,并使应用程序可靠地将此数据存储在内存中,这是Spark性能提升的关键,因为避免了应用程序反复访问磁盘的操作,这种操作的性能代价非常高。

更准确地说,Spark是一个计算框架,而Hadoop中包含计算框架MapReduce和分布式文件系统(HDFS),还有包括在生态圈中的其他系统,如HBase、Hive等。Spark是MapReduce的替代方案,而且兼容HDFS、Hive等分布式存储层,可融入Hadoop的生态系统,以弥补缺失MapReduce的不足。基于MapReduce的计算引擎通常会将中间结果输出到磁盘上,进行存储和容错。出于任务管道承接的考虑,当一些查询转换为MapReduce任务时,往往会产生多个Stage,而这些串联的Stage又依赖于底层文件系统(如HDFS)存储每个Stage的输出结果。而Spark执行的差异在于,将执行模型抽象为通用的有向无环图执行计划,这可以将多Stage的任务串联或者并行执行,而无须将Stage中间结果输出到HDFS中,类似的引擎包括Dryad、Tez。Spark与Hadoop在数据中间进行数据处理的区别如图1-3所示。

由于MapReduce的处理方式会引起较大的处理开销,而Spark抽象出分布式内存存储结构弹性分布式数据集(RDD),进行数据的存储。RDD能支持粗粒度写操作,但对于读取操作,RDD可以精确到每条记录,这使得RDD可用作分布式索引。Spark的特性是能够控制数据在不同节点上的分区,用户可以自定义分区策略,如Hash分区等。Shark和Spark SQL在Spark的基础之上实现了列存储和列存储压缩。MapReduce在数据进行洗牌之前花费了大量的时间来排序,Spark则可减少上述问题带来的开销。因为Spark任务在洗牌中不是所有情景都需要排序,所以支持基于Hash的分布式聚合,调度中采用更通用的任务执行计划图,每一轮次的输出结果在内存缓存。传统Hadoop的MapReduce系统是为了运行长达数小时的批量作业而设计的,在某些极端情况下,提交一个任务的时间延迟非常高。Spark采用事件驱动的类库AKKA启动任务,通过线程池复用线程避免进程或线程启动和切换开销。

图1-3 Spark与Hadoop在数据中间进行数据处理的区别

Spark的易用性来自其通用编程模型,它不限制用户将其应用程序结构化成一堆Map和Reduce操作。Spark的并行程序看起来非常像顺序程序,这使得它们更容易设计和开发。最后,Spark允许用户在同一个应用程序中轻松组合批处理、交互式和流式处理,因此Spark作业的运行速度比同等功能的Hadoop作业快100倍,并且Hadoop需要编写比Spark多2~10倍的代码。

Spark是一个分布式系统,目的是实现大数据量和高运算。同时,它也是扩展性很强的系统,可以在单机上运行,也可以在成百上千的节点上组成集群,每个节点都是一个独立的机器。Spark通过集群管理器(Cluster Manager)管理和协调程序的运行。Spark分布式系统如图1-4所示。

图1-4 Spark分布式系统

Spark应用程序作为独立的集群进程运行,由主程序中的驱动程序(Driver Program)协调。具体来说,要在集群上运行,驱动程序中的SparkContext可以连接到几种类型的集群管理器,如Standalone、Mesos或YARN,可以跨应用程序分配资源。一旦连接,Spark将获取集群中的位于工作节点(Worker Node)上的执行程序(Executor),这些进程是运行计算和存储应用程序数据的进程。接下来,Spark将应用程序代码以JAR或Python文件传递给驱动程序,然后通过SparkContext发送给执行程序。有关这种架构,须注意,每个应用程序都获得自己的执行程序进程,这些进程在整个应用程序的持续时间内保持不变,并在多个线程中运行任务。这有利于将应用程序彼此隔离,即在调度端每个驱动程序安排其自己的任务和执行程序,在不同的虚拟机中运行来自不同应用程序的任务。但是,这也意味着数据在不写入外部存储系统的情况下,不能在不同的Spark应用程序之间共享。

Spark与底层集群管理器无关,只要可以获取执行程序进程,并且彼此进行通信,即使在同时支持其他应用程序(如Mesos/YARN)的集群管理器上运行,也比较容易。驱动程序必须在其生命周期中侦听并接收来自其执行程序的传入连接。因此,驱动程序必须能够从工作节点网络寻址。另外,因为驱动程序调度集群上的任务,所以它应该靠近工作节点运行,最好在同一个局域网上运行,如果想远程发送请求到集群,最好向驱动程序打开一个RPC,并从附近提交操作,而不是在远离工作节点的地方运行驱动程序。该系统目前支持三个集群管理器。

(1)Standalone:Spark包含的一个简单的集群管理器,可以轻松设置集群。

(2)Apache Mesos:也可以运行Hadoop MapReduce和服务应用程序的通用集群管理器。

(3)Hadoop YARN:Hadoop 2中的资源管理器。

在Spark支持的这些集群管理器中,最简单的是Standalone的本地模式(Local),可以实现将Spark部署在一个单机节点上,而且可以实现Spark的所有功能。对于实验教程来说,主要集中在学习Spark的开发,所以熟悉使用Standalone的本地模式,就可以满足基本要求。对于企业应用,需要考虑更高级的YARN或者Mesos环境。

1.2.2 数据格式

在学习Spark系统前,需要了解Spark系统支持的数据格式。Spark可以从Hadoop支持的任何存储源中加载数据,其中包括本地文件系统、HDFS、MapR-FS、Amazon S3、Hive、HBase、JDBC数据库等,以及正在Hadoop集群中使用的任何其他数据源。下面介绍几种重要的数据源。

1.HDFS(Hadoop Distributed File System)

Hadoop是一款支持数据密集型分布式应用程序并以Apache 2.0许可协议发布的开源软件框架。它支持在商品硬件构建的大型集群上运行的应用程序。Hadoop根据谷歌公司发表的MapReduce和谷歌文件系统的论文自行实现而成。Hadoop框架透明地为应用提供可靠性和数据移动。它实现了名为MapReduce的编程范式:应用程序被分区成许多小部分,而每个部分都能在集群中的任意节点上运行或重新运行。此外,Hadoop还提供了分布式文件系统,用以存储所有计算节点的数据,这为整个集群带来了非常高的带宽。MapReduce和分布式文件系统的设计,使得整个框架能够自动处理节点故障,保障应用程序和PB级的数据在成千上万的独立计算机上运行。现在普遍认为,整个Hadoop平台包括内核、MapReduce、分布式文件系统以及一些相关项目,如Hive和HBase等。

2.Amazon S3

Amazon S3的全名为亚马逊简易存储服务(Amazon Simple Storage Service),是亚马逊公司利用其亚马逊网络服务系统提供的网络在线存储服务。经由Web服务界面,包括REST、SOAP与BitTorrent,用户能够轻易把文件存储到网络服务器上。2006年3月,亚马逊公司在美国推出这项服务,2007年11月扩展到欧洲地区。2016年9月,该服务中国区正式商用,与光环新网合作运营。亚马逊公司为这项服务收取的费用是每个月每吉字节需要0.095元美金,如果需要额外的网络带宽与质量,则要另外收费。根据服务级别协议(SLA),S3保证在每月99.9%的时间内可用,即每月停机时间不多于43min。

3.Hive

Apache Hive是一个建立在Hadoop架构之上的数据仓库。它能够提供数据的精炼、查询和分析。Apache Hive起初由Facebook开发,目前也有其他公司使用和开发Apache Hive,如Netflix等。亚马逊公司也开发了一个定制版本的Apache Hive,亚马逊网络服务包中的Amazon Elastic MapReduce包含了该定制版本。Hive提供数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

4.HBase

HBase是一个开源的非关系型分布式数据库(NoSQL),它参考了谷歌的BigTable建模,实现的编程语言为Java。它是Apache软件基金会的Hadoop项目的一部分,运行于HDFS文件系统之上,为Hadoop提供类似于BigTable规模的服务。因此,它可以容错地存储海量稀疏的数据。HBase在列上实现了BigTable论文提到的压缩算法、内存操作和布隆过滤器。HBase的表能够作为MapReduce任务的输入和输出,可以通过Java API访问数据,也可以通过REST、Avro或者Thrift的API访问。虽然最近性能有了显著提升,但HBase还不能直接取代SQL数据库。如今,它已经应用于多个数据驱动型网站,包括Facebook的消息平台。在EricBrewer的CAP理论中,HBase属于CP类型的系统。

5.Cassandra

Cassandra是一个高可靠的大规模分布式存储系统,是一种高度可伸缩的、一致的、分布式的结构化key-value存储方案,集Google BigTable的数据模型与Amazon Dynamo的完全分布式的架构于一身。Cassandra 2007年由Facebook开发,2009年成为Apache的孵化项目。Cassandra使用了Google BigTable的数据模型,与面向行的传统的关系型数据库不同,这是一种面向列的数据库,列被组织成为列族(Column Family),在数据库中增加一列非常方便。对于搜索和一般的结构化数据存储,这个结构足够丰富、有效。

6.JSON

JSON(JavaScript Object Notation)是一种由道格拉斯·克罗克福特构想设计、轻量级的数据交换语言,以文字为基础,且易于阅读。尽管JSON是JavaScript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON数据格式与语言无关,脱胎于JavaScript,但目前很多编程语言都支持JSON格式数据的生成和解析。JSON的官方MIME类型是application/json,文件扩展名是.json。

7.CVS

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其他字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。

8.Parquet

Apache Parquet是Apache Hadoop生态系统的一个免费开源的面向列的数据存储。它类似于Hadoop中可用的其他柱状存储文件格式,即RCFile和优化RCFile。它与Hadoop环境中的大多数数据处理框架兼容,提供了高效的数据压缩和编码方案,具有增强的性能,可以批量处理复杂数据。构建Apache Parquet的开源项目开始于Twitter和Cloudera之间的共同努力。ApacheParquet 1.0的第一个版本于2013年7月发布。从2015年4月27日起,Apache Parquet是Apache Software Foundation(ASF)顶级项目。

9.SequenceFile

SequenceFile是一种扁平(扁平是指没有内部结构)的二进制文件类型,用作Apache Hadoop分布式计算项目中要使用的数据的容器。SequenceFiles广泛用于MapReduce。由于Hadoop对于存储较大文件有最佳效果,因此SequenceFiles提供了一种新的格式用于存储和压缩比较小的文件,这有助于减少所需的磁盘空间容量和I/O要求。例如,SequenceFile可能包含服务器的大量日志文件,其中的键将是一个时间戳,而值将是整个日志文件。SequenceFile分别为写入、读取和排序提供了一个Writer、Reader和Sorter类。

10.协议缓存区(ProtocolBuffers)

协议缓存区是一种序列化数据结构的方法。对于通过管线(Pipeline)或存储数据进行通信的程序开发很有用。这个方法包含一个接口描述语言,描述一些数据结构,并提供程序工具根据这些描述产生代码,用于产生这些数据结构或解析数据流。

11.对象文件(ObjectFiles)

对象文件是一个包含对象代码的文件,意味着可重定位格式的机器代码,通常不能直接执行。对象文件有各种格式,同一对象代码可以打包在不同的对象文件中。对象文件也可以像共享库一样工作。除了对象代码本身之外,对象文件可能包含用于链接或调试的元数据,包括用于解决不同模块之间的符号交叉引用的信息、重定位信息、堆栈展开信息、注释、程序符号、调试或分析信息。

1.2.3 编程语言

Spark可以在Windows和类UNIX系统(如Linux、Mac OS)上运行。在一台机器上本地运行很容易,仅需要在系统上设置安装Java的PATH或指向Java安装的JAVA_HOME环境变量。Spark运行于Java 8+,Python 2.7+/3.4+和R 3.1+。对于Scala API,Spark 2.2.0将需要使用兼容的Scala 2.11.x版本。

选择Apache Spark的编程语言是一个主观问题,因为特定数据科学家或数据分析师使用Python或Scala for Apache Spark的原因可能并不总是适用于其他人。基于独特的用例或特定类型的大数据应用开发,数据专家决定哪种语言更适合Apache Spark编程。数据科学家可以学习Scala、Python、R和Java,以便在Spark中进行编程,并根据功能解决方案的任务效率选择首选语言。

Apache Spark框架具有用于以各种语言进行数据处理和分析的API,包括Java、Scala和Python。Java不支持Read-Evaluate-Print-Loop(REPL)模式,它是选择用于大数据处理的编程语言时的主要条件。Scala和Python都很容易编程,并帮助数据专家快速获得生产力。数据科学家通常喜欢学习Scala和Python,但Python通常是Apache Spark选择的第二语言,Scala是第一选择。表1-1有一些重要的因素可以帮助数据科学家或数据分析师根据自己的要求选择最佳的编程语言。Scala和Python的比较见表1-1。

表1-1 Scala和Python的比较

注意从Spark 2.2.0开始,对于Hadoop 2.6.5之前旧Hadoop版本,以及Java 7和Python 2.6的支持已被删除。Scala 2.10的支持已经不再适用于Spark 2.1.0,可能会在Spark 2.3.0中删除。

1.2.3.1 Java

Java是一种广泛使用的计算机编程语言,拥有跨平台、面向对象、泛型编程的特性,广泛应用于企业级Web应用开发和移动应用开发。任职于Sun公司的詹姆斯·高斯林等人于1990年年初开发Java语言的雏形,最初被命名为Oak,目标设置在家用电器等小型系统的程序语言,应用于电视机、电话、闹钟、烤面包机等家用电器的控制和通信。由于这些智能化家电的市场需求没有预期高,因此Sun公司放弃了该项计划。随着20世纪90年代互联网的发展,Sun公司看到Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布。Java伴随着互联网的迅猛发展而发展,逐渐成为重要的网络编程语言。

Java语言的风格十分接近C++语言,继承了C++语言面向对象技术的核心,舍弃了C++语言中容易引起错误的指针,改用引用,同时移除了原C++中的运算符重载、多重继承特性,改用接口,增加了垃圾回收器功能。在Java SE 1.5版本中引入泛型编程、类型安全的枚举、不定长参数和自动装/拆箱特性。Sun公司对Java语言的解释是:“Java语言是一种简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言”。

Java语言不同于一般的编译语言或直译语言,它首先将源代码编译成字节码,然后依赖各种不同平台上的虚拟机解释执行字节码,从而实现“一次编写,到处运行”的跨平台特性。在早期的虚拟机中,这在一定程度上降低了Java程序的运行效率。但在J2SE 1.4.2发布后,Java的运行速度有了大幅提升。

与传统类型不同,Sun公司在推出Java时就将其作为开放的技术。全球数以万计的Java开发公司被要求所设计的Java软件必须相互兼容。“Java语言靠群体的力量,而非公司的力量”是Sun公司的口号之一,并获得广大软件开发商的认同。这与微软公司倡导的注重精英和封闭式的模式完全不同,此外,微软公司后来推出了与之竞争的.NET平台以及模仿Java的C#语言。后来,Sun公司被甲骨文公司并购,Java也随之成为甲骨文公司的产品。目前,移动操作系统Android大部分的代码都采用Java语言编写。

Spark 2.1.1适用于Java 7及更高的版本。如果使用的是Java 8,则Spark支持使用Lambda表达式简洁地编写函数,否则可以使用org.apache.spark.api.java.function包中的类。

但是,Java 8和之前的版本不支持REPL(Read-Eval-Print Loop,读取、评估、打印循环),但是,对于大型数据和数据科学项目的工程师来说,REPL非常重要。通过交互式shell,开发人员和数据科学家可以轻松地探索和访问数据集以及每一步的运行结果,而不需要完成完整的开发周期。实际上,Java 9中引入了JShell,用来实现REPL功能。下面这个程序显示出“Hello,World!”然后结束运行,注意java.lang包是自动加载的,所以不需要在程序前加入importjava.lang.∗;。

代码1-1

1.2.3.2 Scala

Scala是Scalable Language的简写,是一门多范式的编程语言。洛桑联邦理工学院(EPFL)的Martin Odersky于2001年基于Funnel的工作开始设计Scala。Funnel是把函数式编程思想和Petri网相结合的一种编程语言。Odersky先前的工作是Generic Java和javac(Sun Java编译器)。Java平台的Scala于2003年年底和2004年年初发布,.NET平台的Scala发布于2004年6月。该语言的2.0版本发布于2006年3月。截至2009年9月,最新版本是2.7.6。Scala 2.8的特性包括重写的Scala类库、方法的命名参数和默认参数、包对象,以及Continuation。

Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。它也能运行于CLDC配置的Java ME中。目前还有另一.NET平台的实现,不过版本的更新有些滞后。Scala的编译模型(独立编译、动态类加载)与Java和C#一样,所以Scala代码可以调用Java类库(对于.NET实现,则可调用.NET类库)。Scala包括编译器和类库,以BSD许可证发布。

2009年4月,Twitter宣布已经把大部分后端程序从Ruby迁移到Scala,其余部分也打算迁移。此外,Wattzon已经公开宣称,其整个平台都已经是基于Scala基础设施编写的。Coursera把Scala作为服务器语言使用。Lift是开源的Web应用框架,旨在提供类似Ruby on Rails的东西。因为Lift使用了Scala,所以Lift应用程序可以使用目前所有的Java库和Web容器。

Scala具有以下特征:

1.面向对象特性

Scala是一种纯面向对象的语言,每个值都是对象。对象的数据类型以及行为由类和特质描述。类抽象机制的扩展有两种途径:一种途径是子类继承;另一种途径是灵活的混入机制。这两种途径能避免多重继承的问题。

2.函数式编程

Scala也是一种函数式语言,其函数也能当成值使用。Scala提供了轻量级的语法,用以定义匿名函数,支持高阶函数,允许嵌套多层函数,并支持柯里化(Currying)。Scala的case class及其内置的模式匹配相当于函数式编程语言中常用的代数类型。更进一步,程序员可以利用Scala的模式匹配,编写类似正则表达式的代码处理XML数据。

3.静态类型

Scala具备类型系统,通过编译时检查,保证代码的安全性和一致性。类型系统具体支持以下特性:泛型类、协变和逆变、标注、类型参数的上下限约束、把类别和抽象类型作为对象成员、复合类型、引用自己时显式指定类型、视图、多态方法。

4.扩展性

Scala的设计秉承一项事实,即在实践中,某个领域特定的应用程序开发往往需要特定于该领域的语言扩展。Scala提供了许多独特的语言机制,可以以库的形式无缝添加新的语言结构:任何方法均可用作前缀或后缀操作符;可以根据预期类型自动构造闭包。

5.并发性

Scala使用Actor作为其并发模型,Actor是类似线程的实体,通过邮箱发收消息。Actor可以复用线程,因此可以在程序中使用数百万个Actor,而线程只能创建数千个Actor。在2.10之后的版本中,使用Akka作为其默认Actor实现。以下代码是使用Actor模式的echoServer实现。

代码1-2

Actor模式可以简化并发编程,以便利用多核CPU。以下是用Scala编写的典型Hello World程序。

代码1-3

代码1-4

请注意它与Java的Hello World应用程序有哪些相似之处。一处显著区别在于,Scala版的Hello World程序不通过static关键字把main()方法标记为静态方法,而是用object关键字创建了单例对象。假设该程序保存为HelloWorld.scala文件,接下来可以通过以下命令行进行编译。

代码1-5

若要运行:

代码1-6

这与编译和运行Java的“Hello World”程序是不是很像?事实上,Scala的编译和执行模型与Java是等效的,因而它也兼容Java的构建工具,如Ant。直接使用Scala解释器也可以运行该程序,使用选项-i(从文件加载代码)和选项-e(若要运行额外的代码,就得实际执行HelloWorld对象的方法)即可。

代码1-7

1.2.3.3 Python

Python是一种面向对象、直译式的计算机程序语言。它包含了一组功能完备的标准库,能够轻松完成很多常见的任务。它的语法简单,与其他大多数程序设计语言使用大括号不一样,它使用缩进定义语句块。与Scheme、Ruby、Perl、Tcl等动态语言一样,Python具备垃圾回收功能,能够自动管理内存使用。它经常被当作脚本语言用于处理系统管理任务和网络程序编写,然而它也非常适合完成各种高级任务。Python虚拟机本身几乎可以在所有的操作系统中运行。使用一些诸如py2exe、PyPy、PyInstaller之类的工具可以将Python源代码转换成可以脱离Python解释器运行的程序。Python的官方解释器是CPython,该解释器用C语言编写,是一个由社区驱动的自由软件,目前由Python软件基金会管理。Python支持命令式程序设计、面向对象程序设计、函数式编程、面向侧面的程序设计、泛型编程等多种编程范式。

Python的创始人为吉多·范罗苏姆(Guido van Rossum)。1989年的圣诞节,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承。ABC是由吉多·范罗苏姆参加设计的一种教学语言。吉多·范罗苏姆认为ABC这种语言非常优美和强大,是专门为非专业程序员设计的。但是,ABC语言并没有成功,究其原因,吉多·范罗苏姆认为是非开放造成的。吉多·范罗苏姆决心在Python中避免这一错误,并获得了非常好的效果,完美结合了C语言和其他语言。

就这样,Python诞生了。实际上,第一个实现是在Mac机上。可以说,Python是从ABC发展起来的,主要受到Modula-3(另一种相当优美且强大的语言,是一个小型团体设计的)的影响,并且结合了UNIX shell和C的习惯。

目前,吉多·范罗苏姆仍然是Python的主要开发者,他决定了整个Python语言的发展方向。Python社区经常称呼他是仁慈的独裁者。Python 2.0于2000年10月16日发布,增加了实现完整的垃圾回收,并且支持Unicode。同时,整个开发过程更加透明,社区对开发进度的影响逐渐扩大。Python 3.0于2008年12月3日发布,此版不完全兼容之前的Python源代码。不过,很多新特性后来也被移植到旧的Python 2.6/2.7版本。

Python是完全面向对象的语言,函数、模块、数字、字符串都是对象,并且完全支持继承、重载、派生、多重继承,有益于增强源代码的复用性。Python支持重载运算符,因此Python也支持泛型设计。相对于Lisp这种传统的函数式编程语言,Python对函数式设计只提供了有限的支持。有两个标准库functools和itertools提供了与Haskell和Standard ML中类似的函数式程序设计工具。Python目前也被一些大规模软件开发项目使用,如Zope、Mnet及BitTorrent,其中也包括谷歌的TensorFlow和脸书的PyTorch。Python的支持者较喜欢称它为一种高级动态编程语言,原因是脚本语言泛指仅作简单程序设计任务的语言,如shell script、VBScript等只能处理简单任务的编程语言,并不能与Python相提并论。

Python本身被设计为可扩充的。并非所有的特性和功能都集成到语言核心。Python提供了丰富的API和工具,以便程序员能够轻松地使用C、C++、Cython编写扩充模块。Python编译器本身也可以被集成到其他需要脚本语言的程序内。因此,很多人把Python作为一种胶水语言使用。使用Python将其他语言编写的程序进行集成和封装。在谷歌内部的很多项目,如Google App Engine使用C++编写性能要求极高的部分,然后用Python或Java/Go调用相应的模块。《Python技术手册》的作者马特利(Alex Martelli)说:“这很难讲,不过2004年Python已在谷歌内部使用,谷歌招募了许多Python高手,但在这之前就已决定使用Python,目的是尽量使用Python,在不得已时改用C++;在操控硬件的场合使用C++,在快速开发时使用Python。”

Python的设计哲学是“优雅、明确、简单”。Python开发者的哲学是“用一种方法,最好是只有一种方法做一件事”,因此它和拥有明显个人风格的其他语言不一样。在设计Python语言时,如果面临多种选择,Python开发者一般会拒绝花哨的语法,而选择明确没有或者很少有歧义的语法。这些准则被称为“Python格言”。

Python开发人员尽量避开不成熟或者不重要的优化。一些针对非重要部位的加快运行速度的补丁通常不会被合并到Python内。再加上因为Python属于动态类型语言,动态类型语言是在运行期间检查数据的类型,不得不保持描述变量值的实际类型标记,程序在每次操作变量时,需要执行数据依赖分支,而静态类型语言相对于动态类型语言,在声明变量时已经指定了数据类型和表示方法,根据这一原理导致Python相对于C、Visual Basic等静态类型语言来说运行速度较慢。不过,根据二八定律,大多数程序对速度要求不高。在某些对运行速度要求很高的情况,Python设计师倾向于使用JIT技术,或者使用C/C++语言改写这部分程序,目前可用的JIT技术是PyPy。一个在标准输出设备上输出Hello World的简单程序,这种程序通常作为开始学习编程语言时的第一个程序。

 适用于Python 3.0以上版本以及Python 2.6、Python 2.7

代码1-8

 适用于Python 2.6以下版本以及Python 2.6、Python 2.7

代码1-9

Python也可以单步解释运行。运行Python解释器进入交互式命令行的环境,可以在提示符号>>>旁输入print("Hello,world!"),按Enter键输出结果。

 适用于Python 3.0以上版本以及Python 2.6、Python 2.7

代码1-10

 适用于Python 2.6以下版本以及Python 2.6、Python 2.7

代码1-11

注意低于3.0版本的Python,"Hello,world!"周围不需要括号。Python 3.x与Python 2.x的print语法是不一样的。

1.2.3.4 R

R语言,一种自由软件编程语言与操作环境,主要用于统计分析、绘图、数据挖掘。R本来是由奥克兰大学的罗斯·伊哈卡和罗伯特·杰特曼开发(也因此称为R)的,现在由R开发核心团队负责开发。R基于S语言的一个GNU计划项目,所以也可以当作S语言的一种实现,通常用S语言编写的代码都可以不做修改地在R环境下运行。R的语法来自Scheme。

R的源代码可自由下载使用,也有已编译的可执行文件版本可以下载,可在多种平台下运行,包括UNIX(也包括FreeBSD和Linux)、Windows和Mac OS。R主要是以命令行操作,同时有人开发了几种图形用户界面。R内置多种统计学及数字分析功能。R的功能也可以通过安装包(Packages,用户撰写的功能)增强。因为S的血缘,R比其他统计学或数学专用的编程语言有更强的面向对象功能。R的另一强项是绘图功能,制图具有印刷的素质,也可加入数学符号。虽然R主要用于统计分析或者开发统计相关的软件,但也有人用作矩阵计算。其分析速度可媲美专用于矩阵计算的自由软件GNU Octave和商业软件MATLAB。