一些Application的相关的参数配置,我们会放到env那里,通过application:get_env可以获取到,本身底层实现是基于ETS表,如果读取不频繁的话,微秒级别也是够用的了。

优化方案

老早之前,就看过mochiglobal,超级飞侠这个项目也是使用它来访问用得比较频繁一些env。最近写了篇《游戏常量配置Erlang实现》,又想了下第一个项目其中有用dynamic_compile来动态编译存储app env,当初前辈的实现写得并不好,每加一个env,都要去手动那个env的代码,搞得十分不方便,现在想想可以通过application:get_all_env(‘your_app_name’)来获取所有env的,避免手动取值。后面的项目,我就没用这个东西了,用mochiglobal去代替。

mochiglobal是用ast拼出代码,然后去编译的,不过中间有个不太满意的地方,模块名要list和atom互相转化,这部分开销可以省略,如果我们直接用模块名来访问数据的话。

constant:compile(Mod, KVList)之后,Mod:K()就可以访问到数据了。比如constant:compile(app_env, [{port, 8000}]),app_env:port()就可以拿到8000了。

通过测试,访问100W次,constant的做法大概是30毫秒,mochiglobal大概是400毫秒。另外ETS的话,100W次是1s。

代码

-module(constant).
-export([compile/2]).
compile(Mod, KVList) ->
    Bin = makes(Mod, KVList),
    code:purge(Mod),
    {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin),
    ok.

makes(Module, KVList) ->
    {ok, Module, Bin} = compile:forms(forms(Module, KVList),
                                      [verbose, report_errors]),
    Bin.

forms(Module, KVList) ->
    [erl_syntax:revert(X) || X <- term_to_abstract(Module, KVList)].

term_to_abstract(Module, KVList) ->
    ModuleName = erl_syntax:attribute(
                     erl_syntax:atom(module),
                     [erl_syntax:atom(Module)]),
              
    Export = erl_syntax:attribute(
                 erl_syntax:atom(export),
                 [erl_syntax:list(
                      [erl_syntax:arity_qualifier(
                       erl_syntax:atom(K),
                       erl_syntax:integer(0)) || {K, _} <- KVList])]),

    Functions = [erl_syntax:function(
                    erl_syntax:atom(K),
                    [erl_syntax:clause([], none, [erl_syntax:abstract(V)])]) || {K, V} <- KVList],

    [ModuleName, Export | Functions].

更多