《Erlang程序设计(第2版)》试读:1.1 给并发建模

让我们暂时忘却计算机,我将放眼窗外,告诉你我所看见的。 我看见一个女人正在遛狗,一辆车正试图寻找一个停车位,飞机在头顶上飞过,船只在附近航行。所有这些事都是并行发生的。在本书中,我们将会学习如何将并行活动描述为相互通信的多组并行进程,并学习如何编写并发程序。 在日常用语中,并发(concurrent)、同时(simultaneous)和并行(parallel)等词几乎表示同一个意思。但在编程语言里需要做更精确的区分。具体而言,我们需要区分并发和并行程序。 如果只有一台单核的计算机,是无法在上面运行并行程序的。因为只有一个CPU,而它一次只能做一件事。然而,可以在单核计算机上运行并发程序。计算机在不同的任务之间分享时间,使人产生这些任务是并行运行的错觉。 在接下来的几节中,我们会从一些简单的并发模型起步,然后看看用并发解决问题有哪些益处,最后展示一些突出并发与并行区别的精确定义。 1.1 给并发建模 我们将从一个简单的例子入手,为一种日常情景构建并发模型。设想我看见四个人出去散步,另外还有两条狗和一大群兔子。这些人正在相互交谈,而狗则想要追逐兔子。 要在Erlang里模拟这些,需要编写四个模块,名字分别是person(人)、dog(狗)、rabbit(兔子)和world(世界)。person的代码会放在名为person.erl的文件里,看起来就像是这样: 第1行-module(person).的意思是此文件包含用于person模块的代码。它应该与文件名一致(除了.erl这个文件扩展名)。模块名必须以一个小写字母开头。从技术上说,模块名是一个原子(atom)(关于原子的详细介绍,可参见3.5节)。 模块声明之后是一条导出声明。导出声明指明了模块里哪些函数可以从模块外部进行调用。它们类似于许多编程语言里的public声明。没有包括在导出声明里的函数是私有的,无法在模块外调用。 -export([init/1]).语法的意思是带有一个参数(/1指的就是这个意思,而不是除以1)的函数init可以在模块外调用。如果想要导出多个函数,就应该使用下面这种语法: 方括号[ ... ]的意思是“列表”,因此这条声明的意思是我们想要从模块里导出一个函数列表。 我们也会给dog和rabbit编写类似的代码。 1.1.1 开始模拟 要启动程序,可以调用world:start()。它定义在一个名为world的模块里,这个模块的开头部分就像这样: spawn是一个Erlang基本函数,它会创建一个并发进程并返回一个进程标识符。spawn可以这样调用: 当Erlang运行时系统执行spawn时,它会创建一个新进程(不是操作系统的进程,而是一个由Erlang系统管理的轻量级进程)。当进程创建完毕后,它便开始执行参数所指定的代码。ModName是包含想要执行代码的模块名。FuncName是模块里的函数名,而[Arg1, Arg2, ...]是一个列表,包含了想要执行的函数参数。因此,下面这个调用的意思是启动一个执行函数person:init ("Joe")的进程: spawn的返回值是一个进程标识符(PID,Process IDentifier),可以用来与新创建的进程交互。 与对象类比 Erlang里的模块类似于面向对象编程语言(OOPL,Object-Oriented Programming Language)里的类,进程则类似于OOPL里的对象(或者说类实例)。 在Erlang里,spawn通过运行某个模块里定义的函数创建一个新进程。而在Java里,new通过运行某个类中定义的方法创建一个新对象。 在OOPL里可以用一个类创建数千个类实例。类似地,在Erlang里我们可以用一个模块创建数千甚至数百万个执行模块代码的进程。所有Erlang进程都并发且独立执行,如果有一台百万核的计算机,甚至可以并行运行。 1.1.2 发送消息 启动模拟之后,我们希望在程序的不同进程之间发送消息。在Erlang里,各个进程不共享内存,只能通过发送消息来与其他进程交互。这就是现实世界里的物体行为。 假设Joe想要对Susannah说些什么。在程序里我们会编写这样一行代码: Pid ! Msg语法的意思是发送消息Msg到进程Pid。大括号里的self()参数标明了发送消息的进程(在此处是Joe)。 1.1.3 接收消息 为了让Susannah的进程接收来自Joe的消息,要这样写: 当Susannah的进程接收到一条消息时,变量From会绑定为Joe,这样Susannah就知道消息来自何处,变量Message则会包含此消息。 可以设想扩展一下这个模型,让狗相互发送“汪汪!兔子”的消息,而兔子则相互发送“危险!快躲起来”的消息。 这里应该记住的关键一点是:编程模型基于对现实世界的观察。之所以有三个模块(person、dog和rabbit)是因为例子里有三种并发的事物。world模块的作用是让一个顶级进程来启动这一切。创建两个狗进程是因为有两条狗,创建四个人进程是因为有四个人。程序里的消息则反映出我们在例子中观察到的消息。 我们不会扩展这个模型,而是就此止步,换个话题,来看看并发程序的一些特性。

>Erlang程序设计(第2版)

Erlang程序设计(第2版)
作者: [瑞典] Joe Armstrong
isbn: 711535457X
书名: Erlang程序设计(第2版)
页数: 448
译者: 牛化成
定价: 89.00元
出版社: 人民邮电出版社
装帧: 平装
出版年: 2014-6