我是Erlang的初学者。我想用它来观察教科书的执行情况"用于教学目的的分布式算法(领导者选举,共识......)。在那个阶段,我将系统的拓扑描述为图形(从int到int列表的dict),并基于此,我使用其邻居列表实现并初始化我的节点。它工作正常但似乎有点特别。必须有一种更通用的方法来做到这一点。可以提供帮助的常用库或工具吗?
如果没有,你认为我做的事情有意义吗?见下文。
-module(control).
-export([init/1, init/4]).
% create N processes 1 .. N and return a dict from
% 1..N to Pids
create(_, 0, Dict) -> Dict ;
create(Module, N, Dict) ->
Id = spawn(Module, proc, [nil]),
Id ! init_state,
create(Module, N-1, dict:append(N, Id, Dict)).
% broadcast a Signal to all processes in Dict
broadcast(Dict, Signal) ->
F = fun (_, [Y]) -> Y ! Signal end,
dict : map (F, Dict),
ok.
% send a Signal to process Dict(I)
send(Dict, I, Signal) ->
[Id] = dict : fetch(I, Dict),
Id ! Signal,
ok.
% wait for N ok signals
syncr(0) -> ok;
syncr(N) ->
receive
ok -> io : format("ok received ~n", []), syncr(N-1)
end.
% init neighbors according to topology Graph
init_topology(Dict, Graph) ->
F = fun(X) -> [Res] = dict : fetch(X, Dict), Res end,
IdToPId = fun(L) -> lists : map(F, L) end,
G = fun (I, [Y]) ->
[LId] = dict : fetch(I, Graph),
LPId = IdToPId(LId),
Y ! {neighbors, LPId, self()} end,
dict : map (G, Dict),
ok.
% init all states with unary function Signal : I -> term.
init_state(Dict, Signal) ->
F = fun (I, [Y]) -> Y ! {init, Signal(I), self()} end,
dict : map (F, Dict),
ok.
% init all process according to the given topology and Signal : I -> term
% returns a pair of function Send and Broadcast
init(Module, N, Graph, Signal) ->
Dict = create(Module, N, dict:new()),
init_topology(Dict, Graph),
init_state(Dict, Signal),
syncr(2 * N),
Send = fun (I, S) -> send(Dict, I, S) end,
Broadcast = fun (S) -> broadcast(Dict, S) end,
{ Send, Broadcast }.
% this is a particular instanciation of a consensus algorithm with
% N nodes
% a complete graph topology
% some initialisation of the process states
% the S and B returned functions allows me to interact with the system
% to start the algorithm for instance
init(N) -> {S, B} = control : init(consensus, N, topology : complete(N), fun(_)
-> random : uniform(1000) end), {S,B}.
答案 0 :(得分:1)
OTP有一些处理上述任务的死记硬背的方法。我说" rote"而不是"泛型"因为它们是OTP约定,而不是普遍接受的通用分布式算法实现的解决方案。
OTP在application
/ supervisor
/ gen_
内提供解决方案的事情,如初始化流程图,发送消息,终止,同步信令等等。 *概念。维护进程注册表可以由global
模块,gproc
等实用程序或使用进程组来处理 - 但是您处理进程组的方式似乎更有可能是PID列表更好适合于进程注册表,甚至是当前进程字典(分配给给定进程的整数标签都没有意义,并且如果没有启动消息链本身,则不太可能需要向特定进程N发送消息,其中如果你已经知道它的PID)。
在任何情况下,当您尝试解决实际的现实问题而不是理论问题时,启动流程图的OTP方式最有用。在理论系统中,没有任何失败,代码是完美的,没有用户 - 你正在建模一个理想的案例。在现实世界中,事情破裂,需要监控,漏洞比比皆是,人们绊倒电线和网络电缆,而且日常的常见情况通常是一团糟。真实世界的混乱实际上是OTP旨在帮助应对的事情,它只是偶然地以一种方式提供了一种方法,即将程序声明为流程图 - 事实上这是偶然的,这是为什么"演员模型的语言"和分布式计算理论在Erlang / OTP文档中使用不多。
以OTP方式启动系统的一个副作用是监视,监督和其他一些实际有用的(例如,在用户依赖于系统可用的生产环境中非常有用") application
给你"刚刚发生"无需为监控,调试或临时监控策略添加一堆代码。但这些可能不是你真正关心的事情。
OTP 提供的东西是一组通用的算法实现。在大多数实际系统中(同样,这是Erlang的真正关注点),我们决定将共识的复杂性降至最低,并依靠任意条件强制遵守领导模式,即使这是暂时的破坏性的。
所以一方面"是",Erlang / OTP提供了死记硬背的方法来处理你上面写的大部分代码,但另一方面" No",Erlang / OTP并没有考虑任何特定的分布式计算理论模型,因此其编程文化及其框架已经有意识地决定将特性置于更高的优先级,这些特性提供了在生产中部署强大系统的捷径,并且在实施时优先级较低或坚持理论基础,因此您可能会遗漏一些功能。