如何在Erlang中动态创建atom?

如何在Erlang中动态创建atom?,erlang,Erlang,我试图用动态创建的atom名称注册一对进程,如下所示: 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 kill

我试图用动态创建的atom名称注册一对进程,如下所示:

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\u to\u 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\u lib:format
返回一个潜在的“深度列表”(即它可能包含其他列表),而
list\u to\u atom
需要一个“平面列表”。您可以将
io_lib:format
调用包装在调用
列表:展平
中:

list_to_atom(lists:flatten(io_lib:format("zombie~p", [1]))).
TL;DR

不应该动态生成原子。从您的代码片段中可以看出,您可能正试图找到某种灵活命名进程的方法,但原子不是。使用某种类型的K/V存储,而不是
寄存器/2

讨论

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

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

  • 将键/值对保留在某个地方作为您自己的注册表。这可以是一个单独的进程或一个list/tree/dict/map处理程序来存储
    {Name=>Pid}
    的键/值对
  • 使用模块(与下面的gproc一样,它具有跨集群工作的功能)
  • 使用一个注册表解决方案,比如Ulf Wiger的漂亮小项目。当你真的需要它的时候,它是很棒的(老实说,它不像我看到的那样经常使用)。下面是一篇关于它的使用以及为什么它会这样工作的博文:。gproc的另一个优点是,您将遇到的几乎每个Erlanger都至少对它略知一二
  • 作为第一个选项的变体,将您的程序结构为服务经理和工作人员树(如中所示)。这种模式的一个副作用是,如果您正在做任何非琐碎的事情,服务管理器通常会出于某种原因需要监控其流程,这使得它成为保存PID的键/值注册表的理想场所。当一个程序成熟时,这种模式自然出现是很常见的,特别是当该程序有很高的健壮性要求时。从一开始就将其构建为一组半独立的服务,每个服务的顶部都有一个抽象的管理接口,这通常是一个方便的进化捷径

  • 谢谢,这就成功了!我能够使用
    list\u to\u atom(binary\u to\u list(iolist\u to\u binary(..))
    但使用flatte要好得多。您应该注意,在Erlang VM终止之前,不会对原子进行垃圾收集并使其处于活动状态。这意味着如果你创造了大量的原子,你将使用大量的内存。永远不要这样做。曾经邮政警察局决定删除我的答案,因为我的答案对他们的口味来说太过唐突,但代表了在这个问题上的基本共识和标准答案。不要动态生成原子。曾经你永远不需要这样做,每次你做了一些丑恶的事情都会在宇宙中产生。可惜这个地方完全失去了幽默感-/@zxq9我听说,“动态生成原子可能会导致很多问题,通常不是你想要的”。有什么更好的方法可以做到这一点?我感谢你花时间回答,但你应该知道,听一个没有替代方案的教条式的回答也很难,特别是当我做了你说我不应该做的事情,并且没有小猫被杀的时候很抱歉,如果你的答案确实提供了解决方案,我想我没有看到。因为被接受的答案只展示了如何做一些根本不应该做的事情,我最初的答案旨在以一种令人难忘的方式阻止它的使用。在过去几年的某个时候,这已经成为StackExchange的禁忌,因此根据so标准的节制实践,它被一些显然没有Erlang背景的人无情地杀死。我的新答案是gproc,它工作得很好,但在这种情况下,您可能实际上不需要它。