% (1).编写一个start(AnAtom, Fun)函数来把spawn(Fun)注册为AnAtom。
% 确保当两个并行的进程同时执行start/2时你的程序也能正确工作。
% 在这种情况下,必须保证其中一个进程会成功执行而另一个会失败。
-module(execstart).
-export([create/2]).
start(AnAtom, Fun) ->
case whereis(AnAtom) of
Pid -> io:format("this AnAtom have registered~n");
undefined -> register(AnAtom, spawn(Fun)),
io:format("this is process name:~p~n", [AnAtom])
end.
create(AnAtom, Fun) ->
start(AnAtom, Fun),
start(AnAtom, Fun).
这段程序结果很奇怪,结果二者都不能创建。
将case
的两个子句交换下位置就好。
-module(execstart).
-export([create/2]).
start(AnAtom, Fun) ->
case whereis(AnAtom) of
undefined -> register(AnAtom, spawn(Fun)),
io:format("this is process name:~p~n", [AnAtom]);
Pid -> io:format("this AnAtom have registered~n")
end.
create(AnAtom, Fun) ->
start(AnAtom, Fun),
start(AnAtom, Fun).
因为Pid
匹配的范围大,它可以匹配undefined
,所以第一段代码中undefined
永远不会被匹配。我们在写程序的时候需要注意,范围小的放在前面,范围大的放在后面,避免大范围包含小范围这种情况。
第二段结果
% (2).用12.3节里的程序在你的机器上测量一下进程分裂所需要的时间。
% 在一张进程数量对进程创建时间的图上进行标绘。
% 你能从中得到什么结论。
-module(processes).
-export([max/1]).
max(N) ->
Max = erlang:system_info(process_limit),
io:format("Maximum allowed processes:~p~n", [Max]),
% statistics 返回跟指定类型 Type 相关的系统信息
% runtime 是cpu耗时,wall_clock 是代码运行时间
statistics(runtime),
statistics(wall_clock),
L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock),
lists:foreach(fun(Pid) -> Pid ! die end, L),
U1 = Time1 * 1000 / N,
U2 = Time2 * 1000 / N,
io:format("cpu:~p, time:~p~n", [U1, U2]).
wait() ->
receive
die -> void
end.
for(N, N, F) -> [F()];
for(I, N, F) -> [F() | for(I+1, N, F)].
这里就不做表格了…
从上图能看出,无论是创建100还是100000个进程,cpu和程序耗时都是非常短的,而且进程数量和实现不是线性关系。
% (3).编写一个环形计时测试。创建一个由N个进程组成的环。
% 把一个消息沿着环发送M次,这样总共发送的消息是M*N。
% 记录不同的N和M值所花费的时间
% 用你熟悉的其他编程语言编写一个类似的程序,然后比较一下结果。
% 写一篇博客,把结果在网上发表出来。
-module(sendMessage).
-export([start/2]).
% N 个进程, M 次
start(N, M) ->
sendstart(M, createProcess(N)).
% 创建 N 个进程
createProcess(N) ->
L = for(1, N, fun() -> spawn(fun() -> loop() end) end),
L.
% 起始
sendstart(M, L) ->
% 给第一个进程发送请求,开始绕环发送消息
Pid = getPid(1, L, M),
Pid ! {1, L, M, "hello world"}.
% 进程执行的函数
loop() ->
receive
% {1, [1,2,3,4,5], "hello world"}
{I, L, M, Message} ->
io:format("Pid:~p Recv Message:~p~n", [(I rem lists_size(L))+1,Message]),
% 发送给下一个进程
case getPid(I+1, L, M) of
none -> io:format("have send...~n");
Pid -> Pid ! {I+1, L, M, Message},
loop()
end
end.
% 获得进程的 Pid。
getPid(I, L, M) ->
io:format("...........I:~p~n", [I]),
case lists_size(L) of
Size when I =< Size ->
lists:nth(I, L);
% 注意余数为 0
Size when I > Size, I rem Size =:= 0 ->
lists:nth(Size, L);
Size when I > Size, I =< M ->
lists:nth((I rem Size), L);
Size when I > M ->
none
end.
for(Max, Max, F) -> [F()];
for(I, Max, F) -> [F() | for(I+1, Max, F)].
% 计算lists大小函数
lists_size(L) ->
lists_size(L, 0).
lists_size([_|T], Size) ->
lists_size(T, Size+1);
lists_size([], Size) ->
Size.
至于题目要求性能对比,其实结果很明显,
erlang
的进程不是操作系统范畴的,不需要切换,不需要保存上下文,而c/c++
包括Java
,它们的进程都非常重,上下文切换非常耗时,Linux
下可以看看task_struct
这个结构体,保存进程的信息,而erlang
进程属于虚拟机,非常轻,不共享内存,所以速度肯定非常快。
等闲了再写篇测试博客^_^