使用Erlang而不是其他函数式语言的一个很主要的原因就是 Erlang具有处理并发和分布式计算的编程能力。我们这里说的并发是指程序可以在同一个时点处理多个线程的执行。例如,现代操作系统可以允许你使用Word的同时使用Excel,并且还开着一个电子邮件客户端程序,一个打印的任务在后台也在执行着。当然,对于系统中的每个处理器(CPU)来说同一时刻只能处理一个线程(任务),但是当系统以一定的速率在不同的线程之间进行切换的时候,给人类的感觉就是这些任务都是在同一时间执行的。在一个Erlang程序中很容易创建一个线程进行并发、并行的执行操作,线程之间的通讯也是非常容易的。在Erlang系统中,我们称每一个执行的线程为Process(注意这里的特殊性,不要与其他系统中的进程相混淆)。
(注意:专有名词“Process”经常用于当执行的线程不与别的线程进行数据共享的情况对这种线程的称呼。当这些线程之间共享数据时,我们一般把它们看作一个整体,作为一个Process进程。在 Erlang中,我们往往称呼不共享数据的Thread为Process,并且很多时候是混合着叫的,读者应该自己从上下文中进行分辨)
Erlang的内建函数spawn被用来创建一个新的进程:spawn (Module,Exported_Function,List of Arguments)。考虑下面的例子:
-module(tut14).
-export([start/0,say_something/2]).
say_something(What, 0) ->
done;
say_something(What, Times) ->
io:format("~p~n",[What]),
say_something(What,Times - 1).
start() ->
spawn(tut14,say_something,[hello,3]),
spawn(tut14,say_something,[goodbye,3]),
spawn(tut14,say_something,[qiao,3]),
spawn(tut14,say_something,[ning,3]).
我们可以看到函数say_something的第一个参数表示要“说的话”,第二个参数表示说话的次数。现在我们来看看start函数,它首先启动两个Erlang进程(注意:这里的进程和操作系统的进程并不是一回事,有很大的差别,具体的内容我们会在后面的内容中进行介绍),一个负责输出“hello”3次,另一个负责输出“goodbye”3次。这些进程都是用函数sya_something。注意这个被spawn函数所使用的函数必须从模块中暴露出来,也就是说必须在模块中使用了- export语句暴露的函数。
1> c(tut14).
./tut14.erl:4: Warning: variable 'What' is unused
{ok,tut14}
2> tut14:start().
hello
goodbye
qiao
ning
<0.42.0>
hello
goodbye
qiao
ning
hello
goodbye
qiao
ning
3>
注意这里并不是首先输出“hello”三次,然后再输出 “googdbye”三次,而是交替出现的。这里的<0.63.0>(不同的运行环境和机器都会有不同的具体数值哈)从何而来?这个函数返回值当然是最后一件“事情”的返回值。在start函数中的最后一件事情是:
spawn(tut14, say_something, [goodbye, 3]).
函数spawn返回一个进程标识符(也就是耳熟能详的PID),用来唯一表示一个进程的。所以<0.63.0>是spawn函数被调用后返回的pid。我们将在下面的例子中使用到pid。
同样注意到我们这里在函数io:format中使用了“~p”代替“ ~w”。“~p”大体上和“~w”输出是一致的,但是会将过长的可打印的词组切分为多行,并且明显的缩进每行。这也是将可打印字符作为字符串输出的常见方法。