如何在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值注册一个进程,而不仅仅是原子,并更自由地引用它们。
如果是这种情况,请选择以下四种方法之一:
- 将键/值对保留在某处以充当您自己的注册表。这可以是一个单独的进程或list / tree / dict / map处理程序来存储
#{Name => Pid}
的键/值对。 - 使用global模块(与下面的gproc一样,具有跨群集工作的功能)。
- 使用注册表解决方案,如Ulf Wiger的漂亮的小项目gproc。当你真正需要它的时候真是太棒了(老实说,不像我看到的那样频繁)。这是一篇关于它的使用的博文,以及它为什么会这样运作:http://blog.rusty.io/2009/09/16/g-proc-erlang-global-process-registry/。 gproc的另一个优点是,您遇到的几乎每个Erlanger至少都是熟悉它。
- 第一个选项的变体,将您的程序构建为服务管理器和工作者树(如"Service -> Worker Pattern")。这种模式的一个副作用是,如果你做了一件非常重要的事情,服务经理通常会因为某种原因需要监控其流程,这使得它成为一个理想的候选人来保持一个Key / Pids的价值登记。随着程序的成熟,这种模式最终会逐渐出现,特别是如果该程序具有高稳健性要求,这种情况很常见。从一开始就将其构建为一组半独立服务,每个服务的顶部都有一个抽象的管理界面,这通常是一种方便的进化捷径。
以上是关于如何在Erlang中动态创建原子?的主要内容,如果未能解决你的问题,请参考以下文章
在 Elixir 或 Erlang 中,如何在运行时动态创建和加载模块?
获取 badarith,[erlang,'+',[error,0],[],同时使用 Erlang 片段在 TSUNG 中执行算术运算