((1 つのスレッドで複数の質問をすることをお許しください。それらは関連していると思います。))
こんにちは、モジュールごとのプリコンパイル済みデータに関して、Erlang に存在するベスト プラクティスについて知りたいと思いました。
例:私は、以前から知られている非常に複雑な正規表現を多用するモジュールを持っています。re:compile/2 のドキュメントには次のように書かれています。re の mp() データ型はまったく指定されておらず、ターゲットに依存しないビームが必要な場合はコンパイル時に配置できないため、実行時に RegEx をコンパイルする必要があります。((注: re:compile/2 は単なる例です。メモ化する複雑な関数はすべて私の質問に適合します。))
Erlang のモジュール (できます)には、モジュールがロードされたときに 1 回-on_load(F/A)
実行する必要があるメソッドを示す属性があります。そのため、このメソッドでコンパイルする正規表現を配置し、結果をという名前の新しいets テーブルに保存できます。?MODULE
ダンの回答後に更新されました。
私の質問は次のとおりです。
- 私がetsを正しく理解している場合、そのデータは別のプロセスに保存され(プロセス辞書とは異なる方法で)、etsテーブルの値を取得するには非常にコストがかかります。(私が間違っている場合は、私が間違っていることを証明してください!) スピードアップのために、ets の内容をプロセス辞書にコピーする必要がありますか? (注意: データは決して更新されません。)
- すべてのデータを (多くのテーブル項目ではなく) 1 つのレコードとして 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
.