erlang这门语言的优势主要在于多核编程,编写强大高可用的程序离不开otp框架。otp中主要的行为模式gen_server,虽名为通用服务器,但gen_server的代码并不天生具有处理并发请求的能力,实际上一个gen_server写成的模块是运行在一个线程中的,所有针对它的请求都是序列化处理的,因此gen_server并不具有自动并行处理的能力,还得靠程序员自己实现并行。注意gen_server:call(或者cast)都是这样。
程序员自己如何处理呢?大家知道erlang程序的进程是非常“廉价”的,将任务在spawn出来的进程中处理即可。
erlang并发编程模板如下:
-module(ctemplate).
-compile(export_all).
%% start
%%
%% @spec start() -> pid()
start() ->
% explicit MFA (module, function, args list) enables dynamic code upgrades
spawn(ctemplate, loop, [[]]).
%% remote call
%%
%% @spec rpc(pid(), any()) -> any()
rpc(Pid, Request) ->
Pid ! {self(), Request},
receive
% Pid is in the pattern match to avoid grabbing messages from all
% processes ...
{Pid, Response} ->
Response
end.
%% receive loop handler
%%
%% @spec loop(any()) -> none()
loop(X) ->
receive
Any ->
io:format("Received:~p~n", [Any]),
% tail recursion: this should be last call,
% so it won't consume any stack space
loop(X)
end.
gen_server 的并发处理是在handle的回调函数中使用spawn,如下:
handle_call(Req, From, State) ->
Handler = State#state.store_handler,
spawn(fun(Req) ->
Res = ......, % 在此处理计算得到结果
gen_server:reply(From, Res) % 将结果返回给调用者
end),
{noreply, State}; % 直接返回
使用spawn需要注意 如果你的程序中使用进程字典保存全局变量,需要使用其他方式处理。