如何在Erlang中动态创建原子?

Eli*_*les 2 erlang

我正在尝试使用动态创建的原子名称注册几个进程,如下所示:

keep_alive(Name, Fun) ->
    register(Name, Pid = spawn(Fun)),
    on_exit(Pid, fun(_Why) -> keep_alive(Name, Fun) end).

monitor_some_processes(N) ->
    %% create N processes that restart automatically when killed
    for(1, N, fun(I) ->
                             Mesg = io_lib:format("I'm process ~p~n", [I]),
                             Name = list_to_atom(io_lib:format("zombie~p", [I])),
                             keep_alive(Name, fun() -> zombie(Mesg) end)
                     end).

for(N, N, Fun) -> [Fun(N)];
for(I, N, Fun) -> [Fun(I)|for(I+1, N, Fun)].

zombie(Mesg) ->
    io:format(Mesg),
    timer:sleep(3000),
    zombie(Mesg).
Run Code Online (Sandbox Code Playgroud)

list_to_atom/1电话会导致错误:

43> list_to_atom(io_lib:format("zombie~p", [1])).
** exception error: bad argument
     in function  list_to_atom/1
        called as list_to_atom([122,111,109,98,105,101,"1"])
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?还有,有更好的方法吗?

zxq*_*xq9 5

TL; DR

你不应该动态生成原子.从您的代码片段中可以看出,您可能正在尝试找到灵活命名过程的方法,但原子不是它.使用某种类型的K/V商店而不是register/2.

讨论

原子限制是有原因的.它们应该代表程序的永恒结构,而不是它的当前状态.原子等限制性,我想你是什么真的希望能够做的是注册使用任意二郎价值,而不仅仅是原子的过程,更自由地引用它们.

如果是这种情况,请选择以下四种方法之一:

  1. 将键/值对保留在某处以充当您自己的注册表.这可以是一个单独的进程或list/tree/dict/map处理程序来存储键/值对#{Name => Pid}.
  2. 使用全局模块(与下面的gproc一样,具有跨群集工作的功能).
  3. 使用注册表解决方案,如Ulf Wiger的漂亮的小项目gproc.当你真正需要它的时候真是太棒了(老实说,不像我看到的那样频繁).这是一篇关于它的使用的博客文章,以及它的工作原理:http://blog.rusty.io/2009/09/16/g-proc-erlang-global-process-registry/.gproc的另一个优点是,您遇到的几乎每个Erlanger至少都是熟悉它.
  4. 第一个选项的变体,将您的程序构建为服务管理器和工作者树(如"服务 - >工作者模式").这种模式的一个副作用是,如果你做了一件非常重要的事情,服务经理通常会因为某种原因需要监控其流程,这使得它成为一个理想的候选人来保持一个Key/Pids的价值登记.随着程序的成熟,这种模式最终会自然而然地逐渐消失,特别是如果该程序具有高稳健性要求.从一开始就将其构建为一组半独立服务,每个服务的顶部都有一个抽象的管理界面,这通常是一种方便的进化捷径.