加速和最佳实践:将ets用于每个模块的预先计算的数据
||
((请原谅我在一个线程中问了多个问题。我认为它们是相关的。)
您好,我想知道,关于每个模块的预编译数据,Erlang中存在哪些最佳实践。
示例:我有一个模块,该模块对先验知识,复杂的正则表达式进行大量运算。 re:compile / 2 \的文档说:“编译一次并执行多次要比每次匹配时的编译效率要高得多”。由于未指定re \的mp()数据类型,因此如果要使用目标无关的光束,则无法在编译时放置它,因此必须在运行时编译RegEx。 ((注意:re:compile / 2只是一个示例。要记住的任何复杂函数都适合我的问题。))
Erlang的模块(可以)具有
-on_load(F/A)
属性,表示加载该模块时应执行一次的方法。这样,我可以将正则表达式放在此方法中进行编译,然后将结果保存在名为?MODULE
的新ets表中。
在Dan回答后更新。
我的问题是:
如果我正确地理解ets,则将其数据保存在另一个进程中(以不同的形式保存在进程字典中),并且为ets表检索值非常昂贵。 (如果我错了,请证明我错了!)应该将ets中的内容复制到进程字典中以加快速度吗? (请记住:数据永远不会更新。)
将所有数据作为一条记录(而不是许多表项)放入ets / process字典是否有(很大)缺点?
工作示例:
-module(memoization).
-export([is_ipv4/1, fillCacheLoop/0]).
-record(?MODULE, { re_ipv4 = re_ipv4() }).
-on_load(fillCache/0).
fillCacheLoop() ->
receive
{ replace, NewData, Callback, Ref } ->
true = ets:insert(?MODULE, [{ data, {self(), NewData} }]),
Callback ! { on_load, Ref, ok },
?MODULE:fillCacheLoop();
purge ->
ok
end
.
fillCache() ->
Callback = self(),
Ref = make_ref(),
process_flag(trap_exit, true),
Pid = spawn_link(fun() ->
case catch ets:lookup(?MODULE, data) of
[{data, {TableOwner,_} }] ->
TableOwner ! { replace, #?MODULE{}, self(), Ref },
receive
{ on_load, Ref, Result } ->
Callback ! { on_load, Ref, Result }
end,
ok;
_ ->
?MODULE = ets:new(?MODULE, [named_table, {read_concurrency,true}]),
true = ets:insert_new(?MODULE, [{ data, {self(), #?MODULE{}} }]),
Callback ! { on_load, Ref, ok },
fillCacheLoop()
end
end),
receive
{ on_load, Ref, Result } ->
unlink(Pid),
Result;
{ \'EXIT\', Pid, Result } ->
Result
after 1000 ->
error
end
.
is_ipv4(Addr) ->
Data = case get(?MODULE.data) of
undefined ->
[{data, {_,Result} }] = ets:lookup(?MODULE, data),
put(?MODULE.data, Result),
Result;
SomeDatum -> SomeDatum
end,
re:run(Addr, Data#?MODULE.re_ipv4)
.
re_ipv4() ->
{ok, Result} = re:compile(\"^0*\"
\"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
\"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
\"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])\\\\.0*\"
\"([1-9]?\\\\d|1\\\\d\\\\d|2[0-4]\\\\d|25[0-5])$\"),
Result
.
没有找到相关结果
已邀请:
3 个回复
癸痊醒
惜堡沁戚
剃摧庭峨僳
和
之类的功能的原因之一,这些功能允许在复制数据之前使用更复杂的选择规则。 将数据保存在ETS表中的一个好处是,所有进程都可以访问它,而不仅仅是拥有该表的进程。与将数据保存在服务器中相比,这可以使其效率更高。它还取决于您要对数据执行哪种类型的操作。 ETS只是一个数据存储,并提供有限的原子性。在您的情况下,这可能没问题。 您绝对应该将数据保存在单独的记录中,每个记录分别对应一个不同的已编译正则表达式,因为这将大大提高访问速度。然后,您可以直接获取所需的资源,否则将全部获取,然后在所需的资源之后再次搜索。那样的失败使他们无法进入ETS。 尽管您可以执行诸如在
函数中构建ETS表之类的事情,但对于ETS表却不是一个好主意。这是因为ETS属于进程所有,并且在进程终止时被删除。您永远不会真正知道在哪个过程中调用
函数。您还应避免执行可能会花费很长时间的操作,因为直到完成模块才将其视为已加载。 生成一个解析转换以静态地将编译res的结果直接插入代码中是一个很不错的主意,尤其是在您re的确是静态定义的情况下。正如动态生成,编译模块并将其加载到系统中的想法一样。同样,如果您的数据是静态的,则可以在编译时生成此模块。