不确定这是否可取,但我正在阅读erlang,我正在看一下gen_event,我想知道使用它作为一个完整的面向事件的编程的开销是什么,就像我在Node.Js中使用的那样。
用一个事件处理一个任务和在erlang中生成一个新线程来做同样的任务的开销是什么?
谢谢。
Erlang语言不公开线程,它提供Erlang进程。这些进程由Erlang运行时有效地调度到通常映射到CPU内核的操作系统线程上。它们是轻量级的(包括初始堆在内,32位虚拟机上的内存占用小于4kb),并且是预先调度的,因此阻塞或大量CPU消耗在它们中的任何一个都不会拒绝任何其他进程公平地共享CPU时间。
所以不要害怕生成一个进程来处理你想在系统中服务的每个请求-这是一个很好的初始设计,通常通过并行性为你提供良好的吞吐量,并且倾向于更容易扩展到更多的内核/cpu/节点。
一个额外的好处是,每个进程中的代码可以用直接的过程方式编写:
%% Ask a server to perform a request and await the response from the worker.
request(Server, R) ->
Server ! {new_request, R, self()},
receive {response, Response} -> Response end.
%% Create a server.
start() ->
spawn(?MODULE, server, []).
%% The server code
server() ->
receive
{new_request, R, Sender} ->
%% Spawn a process to handle this request
spawn(?MODULE, process_request, [R, Sender]),
server()
end.
%% The worker code
process_request(R, Sender) ->
A = do_io(),
B = do_cpu_bound_thing(A),
C = do_io(C),
Sender ! {response, C}. % Return the response to the sender
%% Process shuts down cleanly here as there's nothing more to do.
这里我们有两种进程,一种是接受新请求的单一中央服务器进程,另一种是实际完成工作的任意数量的工作进程。单个请求中的错误不会影响服务器进程或其他工作进程,单个工作进程可以根据IO和CPU资源以不同的速率运行。
从这里可以很容易地添加对工作进程的监督,以便我们可以重新启动失败的单个请求,通过在spawn调用中添加'Node'参数来创建工作进程的多机器分布式处理,超时以便客户端在服务器过载或工作进程失败时不会永远阻塞,等等。
您无法通过在gen_event进程中使用多个处理程序来获得上述代码能够实现的并行性。gen_event代码读起来会更复杂,你必须自己交错请求,而不是让运行时为你做。
tl;dr:开销如此之低,其他好处如此之大,以至于您通常(几乎总是)应该生成一个进程,而不是尝试在一个gen_event进程中一次做多个事情。