1、前言
昨晚在Erlang技术交流群问了这样一个问题:我现在有1万多条静态的key-value数据,我现在是直接生成如下代码来使用:
get(key1) ->value1;
get(key2) ->value2;
......
get(keyN) ->valueN.
问题:
1、有没有更高效的方式?
2、Erlang的匹配用的是什么算法?
3、在源码的何处可以看到函数匹配的实现原理?
有人建议用ETS,所以就此进行了简单测试。
2、测试代码
%% @author Rolong
%% 本代码来自瑞仙的Erlang开发博客
%% http://blog.youkuaiyun.com/zhongruixian
-module(test2).
-compile(export_all).
-define(DATA_COUNT, 100000).
-define(ETS_TABLE_NAME, kvs).
%%'运行测试
-spec run(N) -> any() when
N :: non-neg-integer().
run(N)->
F1 = fun(I) -> ets:lookup(?ETS_TABLE_NAME, I rem ?DATA_COUNT) end,
F2 = fun(I) -> kvs:get(I rem ?DATA_COUNT) end,
tester:run(N, [
{"get", F2}
,{"ets", F1}
]).
%%.
%%'写入数据
gen_data() ->
file:delete("src/kvs.erl"),
catch ets:delete(?ETS_TABLE_NAME),
?ETS_TABLE_NAME = ets:new(?ETS_TABLE_NAME,
[public, set, named_table, {keypos, 1}]),
Data = io_lib:format("-module(kvs).~n-export([get/1]).~n", []),
file:write_file("src/kvs.erl", Data, [append]),
gen_kvs(?DATA_COUNT).
gen_kvs(0) ->
Data = io_lib:format("get(_) -> error.", []),
file:write_file("src/kvs.erl", Data, [append]),
ok;
gen_kvs(Key) when Key > 0 ->
% Val = trunc(Key + get_us()), % value类型:integer() (大于32位)
% value类型:term() (复合结构)
% Val = [
% {f, get_us()}
% ,{i, trunc(Key + get_us())}
% ,{b, erlang:md5(integer_to_list(Key))}
% ],
% Val = trunc(Key + get_us()) rem 1000000, % value类型:integer()
% Val = erlang:md5(integer_to_list(Key)), % value类型:binary()
Val = {value, Key + 100}, % value类型:tuple()
Data = io_lib:format("get(~w) -> ~w;~n", [Key, Val]),
file:write_file("src/kvs.erl", Data, [append]),
ets:insert(?ETS_TABLE_NAME, {Key, Val}),
gen_kvs(Key - 1).
%%.
%%'Utils
get_us()->
{M, S, U} = erlang:now(),
M * 1000000000 + S * 1000 + U / 1000.
%%.
%% vim: set filetype=erlang foldmarker=%%',%%. foldmethod=marker:
3、运行测试
相同的键值对数据分别写入ets与erl文件,
不同的value数据类型同样执行1000w次的测试结果如下:
% value类型:tuple()
% 数据总量:1w
% test2:run(10000000).
% "get" [total: 546(546)ms avg: 0.055(0.055)us]
% "ets" [total: 2340(2480)ms avg: 0.234(0.248)us]
% ========================================================================
% get = 546.00ms [ 100.00%] 546.00ms [ 100.00%]
% ets = 2340.00ms [ 428.57%] 2480.00ms [ 454.21%]
% ========================================================================
% value类型:tuple()
% 数据总量:10w
% test2:run(10000000).
% "get" [total: 515(515)ms avg: 0.051(0.051)us]
% "ets" [total: 3588(3604)ms avg: 0.359(0.360)us]
% ========================================================================
% get = 515.00ms [ 100.00%] 515.00ms [ 100.00%]
% ets = 3588.00ms [ 696.70%] 3604.00ms [ 699.81%]
% ========================================================================
% value类型:binary()
% 数据总量:1w
% test2:run(10000000).
% "get" [total: 515(515)ms avg: 0.051(0.051)us]
% "ets" [total: 2465(2464)ms avg: 0.247(0.246)us]
% ========================================================================
% get = 515.00ms [ 100.00%] 515.00ms [ 100.00%]
% ets = 2465.00ms [ 478.64%] 2464.00ms [ 478.45%]
% ========================================================================
% value类型:binary()
% 数据总量:10w
%
% kvs.erl文件为8M,我机器上已无法编译(进程内存分配达到上限)
% value类型:integer()
% 数据总量:10w
% test2:run(10000000).
% "get" [total: 499(515)ms avg: 0.050(0.051)us]
% "ets" [total: 3307(3307)ms avg: 0.331(0.331)us]
% ========================================================================
% get = 499.00ms [ 100.00%] 515.00ms [ 100.00%]
% ets = 3307.00ms [ 662.73%] 3307.00ms [ 642.14%]
% ========================================================================
% value类型:integer() (大于32位)
% 数据总量:10w
% test2:run(10000000).
% "get" [total: 546(546)ms avg: 0.055(0.055)us]
% "ets" [total: 3744(3837)ms avg: 0.374(0.384)us]
% ========================================================================
% get = 546.00ms [ 100.00%] 546.00ms [ 100.00%]
% ets = 3744.00ms [ 685.71%] 3837.00ms [ 702.75%]
% ========================================================================
% value类型:term() (复合结构)
% 数据总量:1w
% test2:run(10000000).
% "get" [total: 530(531)ms avg: 0.053(0.053)us]
% "ets" [total: 3089(3447)ms avg: 0.309(0.345)us]
% ========================================================================
% get = 530.00ms [ 100.00%] 531.00ms [ 100.00%]
% ets = 3089.00ms [ 582.83%] 3447.00ms [ 649.15%]
% ========================================================================
4、测试结果
(1)、静态键值对(key-value)数据直接写成erl文件编译后读取比读ETS表快6倍左右;(2)、数据量越大,数据结构越复杂,两者差距越明显;
(3)、erl文件太大(大于10M)时,编译会很慢(大于1分钟);
(4)、数据量在1w左右,写成erl文件3M内,建议用erl文件形式更快更直接。
PS:我的测试不能保证公平性,还望大神们提点。
本文来自瑞仙的 Erlang开发博客
http://blog.youkuaiyun.com/zhongruixian
原文地址:http://blog.youkuaiyun.com/zhongruixian/article/details/44885953