Скорость- вверх и лучшие практики: Использование ets для предварительно вычисленных данных для каждого модуля

((Простите меня, что я задаю более одного вопроса в одном потоке. Я думаю, что они связаны.))

Привет, я хотел знать, что в Erlang существуют лучшие практики в отношении предварительно скомпилированных данных для каждого модуля.

Пример: У меня есть модуль , который в значительной степени оперирует априори известными, очень сложными регулярными выражениями . Документация re: compile / 2 гласит: «Компиляция один раз и выполнение много раз намного эффективнее, чем компиляция каждый раз, когда требуется сопоставление». Поскольку тип данных re's mp () никоим образом не указан, и как таковой не может быть помещен во время компиляции, если вам нужен независимый от цели луч, нужно компилировать RegEx во время выполнения. (( Примечание: re: compile / 2 является только примером. Любая сложная функция для мемоизации подойдет под мой вопрос.))

Модуль Erlang (может) имеет -on_load (F / A) Атрибут , обозначающий метод, который должен выполняться один раз при загрузке модуля . Таким образом, я мог бы разместить свои регулярные выражения для компиляции в этом методе и сохранить результат в новой таблице ets с именем ? MODULE .

Обновлено после ответа Дэна.

My вопросы:

  • Если я правильно понимаю 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
.

]

9
задан kay 31 May 2011 в 11:29
поделиться