【问题标题】:distributed algorithms simulation in erlangerlang中的分布式算法模拟
【发布时间】:2015-04-11 22:22:36
【问题描述】:

我是 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}.

【问题讨论】:

    标签: algorithm erlang distributed


    【解决方案1】:

    OTP 有一些死记硬背的方法来处理上述任务。我说“死记硬背”而不是“通用”,因为它们是 OTP 约定,而不是通用分布式算法实现的普遍接受的解决方案。

    诸如初始化进程图、消息传递、终止、同步信号等是 OTP 在application/supervisor/gen_* 概念中提供的解决方案。维护进程注册表可以由global 模块、gproc 等实用程序或使用进程组来处理——但是您处理进程组的方式似乎更可能是 PID 列表比进程更适合注册表,甚至您当前的进程字典(分配给给定进程的整数标签是没有意义的,如果没有启动消息链本身,您不太可能需要向特定进程 N 发送消息,在这种情况下,您已经可以知道它的PID)。

    在任何情况下,当您尝试解决实际问题而不是理论上的问题时,启动进程图的 OTP 方式最有用。在理论系统中,没有什么会失败,代码是完美的,并且没有用户——你正在建模一个理想的案例。在现实世界中,事情中断,需要监控,漏洞比比皆是,人们被电线和网络电缆绊倒,日常的常见情况通常是一团糟。现实世界的混乱确实是 OTP 旨在帮助应对的,它只是偶然地这样做,它提供了一种将程序声明为进程图的死记硬背的方法——事实上这是偶然的,这是为什么Erlang/OTP 文档中很少使用“参与者模型”和分布式计算理论的语言。

    以 OTP 方式启动系统的一个副作用是监视、监督和其他一些实际有用的东西(例如,“在用户依赖系统可用的生产环境中有用”)application 为您提供“只是发生”,而不需要添加一堆代码来监控、调试或临时监督策略。但这些可能不是你真正关心的事情。

    OTP提供的是一组通用的共识算法实现。在大多数实际系统中(这也是 Erlang 的真正关注点),决定将共识的复杂性降至最低,并依靠任意条件强制遵守领导模型,即使这会暂时具有破坏性。

    所以一方面“是”,Erlang/OTP 提供了死记硬背的方法来处理您上面编写的大部分代码,但另一方面,“否”,Erlang/OTP 没有设计任何特定的分布式理论模型考虑到计算,因此它的编程文化和它的框架有意识地决定将更高的优先级放在为在生产中部署健壮系统提供快捷方式的特性上,而对实现或遵守理论基础的优先级较低,所以你的一些功能可能会丢失。

    【讨论】:

    猜你喜欢
    • 2014-07-05
    • 2013-02-26
    • 2011-10-11
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    相关资源
    最近更新 更多