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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在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).

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"])

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

答案

io_lib:format返回一个可能的“深度列表”(即它可能包含其他列表),而list_to_atom需要一个“平面列表”。您可以在调用io_lib:format时包装lists:flatten调用:

list_to_atom(lists:flatten(io_lib:format("zombie~p", [1]))).
另一答案

TL; DR

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

讨论

原子限制是有原因的。它们应该代表程序的永恒结构,而不是它的当前状态。原子是如此限制,我想你真正希望能够做的是使用任意Erlang值注册一个进程,而不仅仅是原子,并更自由地引用它们。

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

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

以上是关于如何在Erlang中动态创建原子?的主要内容,如果未能解决你的问题,请参考以下文章

在 Elixir 或 Erlang 中,如何在运行时动态创建和加载模块?

如何在erlang中应用热代码交换功能作为补丁?

Erlang:为什么这会以'badarith'异常失败?

你如何在片段中膨胀动态创建的对象?

获取 badarith,[erlang,'+',[error,0],[],同时使用 Erlang 片段在 TSUNG 中执行算术运算

Erlang ETS 原子和隔离