- Scala并发编程(第2版)
- (瑞士)亚历山大·普罗科佩茨
- 3641字
- 2021-08-17 17:17:55
前言
并发计算无处不在。随着消费者市场中多核处理器的崛起,人们对并发计算的需求已经在开发者世界中掀起巨大波澜。曾几何时,并发编程还只是一个学术名词,常常被解释为程序和计算机系统中的异步计算。现在,并发编程已经成为软件开发中被广泛遵循的方法论之一。于是,高级的并发框架和软件库如雨后春笋般大量涌现,让我们见证了并发计算领域的复兴。
随着现代程序语言和并发模型的抽象层次不断提高,确定它们的使用场合和时机就显得比较关键了。仅仅了解经典的并发和同步等基础原语(比如线程、锁和监控器等)已经不够。高层次的并发框架可解决很多传统并发计算面临的难题,而且可以针对具体任务进行裁剪,于是其逐渐占领了并发计算市场。
本书用 Scala 描述高层次的并发编程,详细解释了不同的并发计算主题,并覆盖了并发编程的基础理论。同时,本书还描述了几种现代并发计算框架,详细介绍了它们的语义及用法。在介绍重要的并发抽象概念的同时,本书也讲解了它们在实际场景中的应用。有理由相信,读者通过本书既可以获得对并发编程理论的扎实理解,也能学会如何编写正确而高效的并发程序。掌握这些实用技能,读者将能走出成为一名现代并发计算专家的第一步。本书的编写过程是令人愉快的,希望读者也能享受同样愉悦的阅读过程。
组织结构
本书各章分别介绍并发编程的不同的主题。其中包含 Scala 运行时中的基础并发计算API,以及更复杂的并发原语,还有一些高层次的并发抽象模型。
● 第1章:概述。本章介绍并发编程的必要性及背景。同时,本章介绍Scala语言基础知识,这对读者理解本书后面的内容是必要的。
● 第2章:JVM和JMM上的并发性。本章介绍并发编程的基础知识,包含如何使用线程、如何保护共享内存,以及JMM。
● 第3章:并发编程的传统构造模块。本章介绍经典并发编程的一些工具,比如线程池、原子性变量、并发容器,重点介绍它们在Scala语言中的体现。本书关注的是现代高层次并发编程框架。因而,本章只回顾传统并发编程技术,并不会深入展开讲解。
● 第4章:基于Future和Promise的异步编程。本章专门针对Scala并发框架进行讲解,介绍Future和Promise的API,以及它们在异步编程中的正确使用方法。
● 第5章:数据并行容器。本章描述Scala的并行容器框架,介绍如何将容器操作并行化,以及如何评估性能的提升。
● 第6章:基于响应式扩展的并发编程。本章介绍如何在基于事件和异步的编程中使用响应式扩展框架,介绍事件流操作和容器操作之间的对应关系、如何让事件在线程之间传递,以及如何使用事件流设计响应式用户界面。
● 第7章:软件事务性内存。本章介绍用于事务性编程的ScalaSTM库,它提供了一种更安全、更直观的共享内存模型。在本章中,读者将学习如何通过可扩展内存事务来保护共享数据,同时减少死锁和竞态条件发生的风险。
● 第8章:角色模型。本章介绍角色模型和Akka框架。在本章中,读者将学习如何透明地在多个机器上构建消息传递分布式程序。
● 第9章:并发编程实践。本章总结前面介绍的不同并发库。在本章中,读者将学习如何在解决实际问题时选择正确的并发抽象模型,以及如何在设计大型并发应用时结合使用多个并发抽象模型。
● 第10章:反应器编程模型。本章介绍反应器编程模型,重点介绍如何更好地在并发和分布式程序中实现模拟化组合。这种新的模型将并发和分布式编程模式分解为模块化组件,称为协议。
推荐读者依次阅读本书这些章节的内容,也可以不必完全如此。如果读者已经对第2章的内容很熟悉,可以直接跳过这一章。唯有第9章依赖于前面的内容,因为这一章是对前面章节的内容的总结。第10章则用于帮助读者理解角色和事件流的工作方式。
阅读本书所需的条件
下面主要介绍阅读和理解本书所需的必要条件,包括JDK(这是运行Scala所必需的)的安装和如何使用简单构建工具(Simple Build Tool,SBT)运行示例程序。
本书中并不要求使用集成开发环境(Integrated Development Environment,IDE),使用什么工具编写代码完全由读者自行决定。原则上,任何文本编辑器都是可以的,包括但不限于Vim、Emacs、Sublime Text、Eclipse、IntelliJ IDEA和Notepad++等。
安装JDK
Scala程序并不会被直接编译成本地机器码,所以无法在硬件平台上作为可执行程序来运行。Scala 编译器会生成一种称为 Java 字节码的中间代码,这种中间代码需要运行在Java虚拟机(Java Virtual Machine,JVM)软件上。下面将介绍如何下载和安装JDK, JDK中就包含了JVM和其他一些有用的工具。
JDK的软件实现有很多,它们来自不同的软件厂商,本书建议使用Oracle JDK。下载和安装JDK的步骤如下。
1.进入官网下载。
2.如果官网打不开,则可以在搜索引擎中搜索关键字“JDK下载”。
3.找到Java SE的下载链接,在官网上选择正确的版本并下载,比如操作系统可以是Windows、Linux或macOS,系统架构可以是32位也可以是64位。
4.如果使用Windows,则直接运行安装包。如果使用macOS,则打开.dmg文件并安装JDK。如果使用Linux,先将压缩包解压到某个目录,比如XYZ,然后将其加到环境变量PATH中。
export PATH=XYZ/bin:$PATH
5.现在,读者应该可以在终端中运行java和javac命令了。在终端中试一试javac命令,看看系统能不能找得到JDK(本书中不会直接使用这个命令,这里只是用它来验证JDK是否已经装好)。读者的操作系统中有可能已经安装过JDK了,验证方式同样是使用javac命令。
安装和使用SBT
SBT是Scala工程所用的命令行构建工具。它的用途包括编译Scala代码、管理依赖项、持续性编译和测试、部署等。纵观全书,示例代码都是用SBT来管理依赖项和运行的。
安装SBT的步骤如下。
1.进入Scala官网。
2.下载读者所用操作系统对应的安装文件。如果使用Windows,这是个.msi安装包;如果使用Linux或macOS,这是一个.zip或.tgz压缩包。
3.安装SBT。在Windows下可直接运行安装包;在Linux或macOS下,将压缩包解压到用户主目录下即可。
安装好SBT之后,按照下面的步骤可生成一个新的SBT工程。
1.打开Windows下的命令提示符窗口,或Linux/macOS下的终端窗口。
2.创建一个名称为scala-concurrency-examples的目录(在Linux中)。
$ mkdir scala-concurrency-examples
3.进入scala-concurrency-examples目录。
$ cd scala-concurrency-examples
4.创建本示例中的唯一的源码目录。
$ mkdir src/main/scala/org/learningconcurrency/
5.用选定的文本编辑器创建一个构建定义文件build.sbt。此文件定义了工程属性。在工程根目录(scala-concurrency-examples)中创建这个文件,并加入如下定义(注意,空行是必要的)。
name := "concurrency-examples" version := "1.0" scalaVersion := "2.11.1"
6.最后,回到终端,从工程根目录运行SBT。
$ sbt
7.SBT会打开一个交互式命令行界面,可以输入一些SBT构建命令。
现在,读者可以开始编写Scala程序了。打开编辑器,在目录src/main/scala/org/learningconcurrency中创建一个源码文件HelloWorld.scala。并在HelloWorld. scala中加入如下内容。
package org.learningconcurrency object HelloWorld extends App { println("Hello, world!") }
回到终端窗口的SBT交互式命令行界面,运行如下命令。
> run
会得到如下输出。
Hello, world!
上述步骤对于本书中大部分示例来说已经够用。不过,偶尔还会用到外部依赖库,SBT会从标准软件仓库中自动解析和下载这些库。有时候,还需要指定其他的软件仓库,所以可以在build.sbt中加入如下内容。
resolvers ++= Seq( "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots", "Sonatype OSS Releases" at "https://oss.sonatype.org/content/repositories/releases", "Typesafe Repository" at "http://repo.typesafe.com/typesafe/maven-releases/" )
这样,所有必需的软件仓库都已经就绪,然后就可以添加具体的库了。在 build.sbt文件中加入下列内容,它表示添加Apache Commons IO库。
libraryDependencies += "commons-io" % "commons-io" % "2.4"
修改完build.sbt之后,有必要重新加载正在运行的SBT实例。在SBT交互式命令行中,执行如下命令。
> reload
这样,SBT就能检测到构建定义文件中的任何改动,并加载必要的外部依赖库。
不同的 Scala 库保存在不同的命名空间中,称为包。为获得某个包的内容,需要使用import语句。本书中的示例在第一次使用某个并发库时,会给出其import语句,但后续再次出现该并发库时,就不会重复同样的语句了。
类似地,为了更简练,本书也会在代码示例中避免出现重复的包声明。只需要让每一章使用同一个包命名规则即可。比如,第2章所有代码都放在名为org. learningconcurrency. ch2的包中。这一章中的代码示例都以如下代码开头。
package org.learningconcurrency package ch2
本书是关于并发计算和异步编程的书。许多示例启动的是并发计算,它们会在主程序停止之后仍然继续执行。为确保这些并发计算总能结束,本书中的示例都是在 SBT 本身的JVM实例上运行的。所以,需要在build.sbt文件中加入下面一行内容。
fork := false
如果某个示例需要用到另一个JVM进程,书中会给出明确的提示。
使用Eclipse、IntelliJ IDEA或其他IDE
使用诸如Eclipse或IntelliJ IDEA的IDE的一个好处是用户可以一气呵成地编写、编译和运行Scala代码。这时就不再需要安装SBT了。虽然本书建议读者使用SBT运行示例代码,但使用IDE也是没问题的。不过,使用IDE运行本书的示例代码会有一个问题,即Eclipse和IntelliJ IDEA等IDE会在单独的JVM进程中运行程序。前面提过,某些并发计算会在主程序结束之后仍然继续运行,为了确保它们总能正常结束,用户有时需要在主程序后面添加 sleep 语句,以延缓主程序的退出。本书的大部分示例代码会加上sleep语句,但有时候读者需要自行加上。
本书的目标读者
本书主要面向学过串行 Scala 程序且希望了解如何编写并发程序的开发者。本书假设读者对 Scala 程序语言有基本的了解。本书的目的是展示如何编写并发程序,因此会坚持只使用Scala中的简单功能。即使只对Scala有初步了解,读者也应该能容易地理解书中的各种并发编程主题。
但这并不是说本书只面向Scala开发者。不管是Java、.NET,还是其他的程序语言的爱好者,都能够通过阅读本书有所收获。从这一方面看,读者具备基本的面向对象编程或函数式编程经验应该就足够了。
广义来讲,本书其实是一本介绍现代并发编程的图书。即使只是略懂多线程计算或JVM并发模型,读者也能从本书中学到很多关于现代高层次并发编程工具的知识。书中提到的很多并发库也只是刚开始进入主流编程语言行列,有些还算得上是前沿技术。