我在进程A上创建了一个digraph术语,我希望将这个有向图传递给另一个节点上的进程。每当我在另一个进程中使用这个有向图时,我会收到错误,例如:
** {badarg,
[{ets,insert,[598105,{"EPqzYxiM9UV0pplPTRg8vX28h",[]}],[]},
{digraph,do_add_vertex,2,[{file,"digraph.erl"},{line,377}]},
假设有向图基于ETS,看起来这更加复杂,使得digraph在它创建的过程中几乎是独立的。我发现此条目显示了类似的问题:ETS on a different process
我知道我可以在服务器中创建有向图,然后通过otp消息连接到它,但我不能在我的架构中这样做。所有节点都可以使用旨在将状态作为条款传递的特定方法进行通信。
在我看来,不能在不同的节点之间发送不能直接相互通信的有向图。总的来说,似乎无法直接序列化有向图。我在想,我可以将有向图“展开”为顶点和边的列表,然后在另一个进程上传输并重新创建它(不是高效,执行或优雅)。有关更好地序列化的想法吗?有没有办法将有向图状态序列化为ETS商店?
有什么想法吗?
答案 0 :(得分:2)
我有一个解决方案,但它依赖于digrapgh:new()返回的变量的结构,所以我不确定它是否与未来的版本兼容。
D = digraph:new(),
...
%some code modifying D
...
{digraph,Vertices,Edges,Neighbours,Cyclic} = D, % get the table Id of the 3 tables containing D values
% It should be preferable to use the record definition of the digraph module
%-record(digraph, {vtab = notable :: ets:tab(),
% etab = notable :: ets:tab(),
% ntab = notable :: ets:tab(),
% cyclic = true :: boolean()}).
LV = tab2list(Vertices),
LE = tab2list(Edges),
LN = tab2list(Neighbours),
...
% then serialize and send all this variables to the target node, ideally in one single tuple like
% {my_digraph_data,LV,LE,LN,Cyclic} or using refs to avoid the mix of messages,
% and on reception on the remote node:
receive
{my_digraph_data,LV,LE,LN,Cyclic} ->
Dcopy = digrapgh:new(Cyclic),
{digraph,Vertices,Edges,Neighbours,_Cyclic} = Dcopy,
ets:insert(Vertices,LV),
ets:insert(Edges,LE),
ets:insert(Neighbours,LN),
Dcopy;
...
就是这样。
答案 1 :(得分:2)
你可以像这样序列化/反序列化一个有向图;
serialize({digraph, V, E, N, B}) ->
{ets:tab2list(V),
ets:tab2list(E),
ets:tab2list(N),
B}.
deserialize({VL, EL, NL, B}) ->
DG = {digraph, V, E, N, B} = case B of
true -> digraph:new();
false -> digraph:new([acyclic])
end,
ets:delete_all_objects(V)
ets:delete_all_objects(L)
ets:delete_all_objects(N)
ets:insert(V, VL)
ets:insert(E, EL)
ets:insert(N, NL)
DG.
这是我用来测试它的代码;
passer() ->
G = digraph:new(),
V1 = digraph:add_vertex(G),
V2 = digraph:add_vertex(G),
V3 = digraph:add_vertex(G),
digraph:add_edge(G, V1, V2, "edge1"),
digraph:add_edge(G, V1, V3, "edge2"),
Pid = spawn(fun receiver/0),
Pid ! serialize(G).
receiver() ->
receive
SG = {_VL, _EL, _NL, _B} ->
G = deserialize(SG),
io:format("Edges: ~p~n", [digraph:edges(G)]),
io:format("Edges: ~p~n", [digraph:vertices(G)])
end.
非常丑陋的解决方案但有效。我认为这是在节点之间传递有向图的唯一方法,因为ets表不能在节点之间共享。
编辑:删除不必要的循环