瀏覽代碼

代码添加

master
AICells 5 年之前
父節點
當前提交
9ed0a0a909
共有 19 個檔案被更改,包括 987 行新增658 行删除
  1. +14
    -1
      src/docs/erlang数据结构相关.md
  2. +60
    -0
      src/testCase/DsTest/arrayDs.erl
  3. +52
    -0
      src/testCase/DsTest/atomicsDs.erl
  4. +63
    -0
      src/testCase/DsTest/dictDs.erl
  5. +63
    -0
      src/testCase/DsTest/etsOrdDs.erl
  6. +63
    -0
      src/testCase/DsTest/etsSetDs.erl
  7. +57
    -0
      src/testCase/DsTest/gb_setsDs.erl
  8. +65
    -0
      src/testCase/DsTest/gb_treesDs.erl
  9. +59
    -0
      src/testCase/DsTest/listsDs.erl
  10. +68
    -0
      src/testCase/DsTest/mapsDs.erl
  11. +63
    -0
      src/testCase/DsTest/orddictDs.erl
  12. +58
    -0
      src/testCase/DsTest/ordsets.erl
  13. +67
    -0
      src/testCase/DsTest/pdDs.erl
  14. +49
    -0
      src/testCase/DsTest/persistentTermDs.erl
  15. +57
    -0
      src/testCase/DsTest/setsDs.erl
  16. +55
    -0
      src/testCase/DsTest/tupleDs.erl
  17. +73
    -0
      src/testCase/DsTest/utTestDs.erl
  18. +0
    -656
      src/testCase/utTestDS.erl
  19. +1
    -1
      src/testCase/utTestMd5.erl

+ 14
- 1
src/docs/erlang数据结构相关.md 查看文件

@ -277,4 +277,17 @@ Unique Integers on a Runtime System Instance
array有两种模式,一种固定大小,另一种按需自动增长大小,但不会自动收缩
支持稀疏存储,执行array:set(100,value,array:new()),那么[0,99]都会被设置为默认值(undefined),该默认值可修改。
在实现上,array最外层被包装为一个record:
... 其他等待被添加
... 其他等待被添加
%% Module Description
%% sets sets, a collection of unique elements.
%% gb_sets sets, but based on a general balanced data structure
%% gb_tree a general balanced tree
%% dict maps, also called associative arrays
%% queue double-ended queues
%% ets hash tables and ordered sets (trees), stored outside the process
%% dets on-disk hash tables
(请注意:不常用的模块ordset和 orddict只是有序列表,因此对于诸如插入之类的常见操作具有O(n))
% Suggestion:
% elments count: 0 - 100 | 100 - 10000 | 10000 -
% our select : list | ets | gb_tree

+ 60
- 0
src/testCase/DsTest/arrayDs.erl 查看文件

@ -0,0 +1,60 @@
-module(arrayDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num - 1, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num - 1, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num - 1, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num - 1, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num - 1, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, not_support}),
exit(normal).
init(Num) ->
array:new(Num, fixed).
insert(0, Ds) ->
Key = utTestDs:makeK(0),
array:set(0, utTestDs:makeV(0), Ds);
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = array:set(Num, utTestDs:makeV(Num), Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Key = utTestDs:makeK(0),
Value = array:get(0, Ds),
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = array:get(Num, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Key = utTestDs:makeK(0),
array:set(0, utTestDs:makeV2(0), Ds);
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = array:set(Num, utTestDs:makeV2(Num), Ds),
update(Num - 1, NewDs).
for(0, Ds) ->
Value = array:get(0, Ds),
Ds;
for(Num, Ds) ->
Value = array:get(Num, Ds),
for(Num - 1, Ds).
delete(Num, Ds) ->
ok.

+ 52
- 0
src/testCase/DsTest/atomicsDs.erl 查看文件

@ -0,0 +1,52 @@
-module(atomicsDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, not_support}),
exit(normal).
init(Num) ->
atomics:new(Num, []).
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
atomics:put(Ds, Num, Num),
insert(Num - 1, Ds).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Value = atomics:get(Ds, Num),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
NewDs = atomics:add(Ds, Num, 1),
update(Num - 1, NewDs).
for(0, Ds) ->
Ds;
for(Num, Ds) ->
atomics:get(Ds, Num),
for(Num - 1, Ds).
delete(0, Ds) ->
ok.

+ 63
- 0
src/testCase/DsTest/dictDs.erl 查看文件

@ -0,0 +1,63 @@
-module(dictDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDictF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDictF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
dict:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
NewDs = Ds:store(Key, Value, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = Ds:find(Key, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
NewDs = Ds:store(Key, Value, Ds),
update(Num - 1, NewDs).
for(Num, Ds) ->
Fun =
fun(Key, Value, Acc) ->
Value
end,
List = Ds:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = Ds:erase(Key, Ds),
delete(Num - 1, NewDs).

+ 63
- 0
src/testCase/DsTest/etsOrdDs.erl 查看文件

@ -0,0 +1,63 @@
-module(etsOrdDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
ets:new(test, [ordered_set]).
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
Ds:insert(Ds, {Key, Value}),
insert(Num - 1, Ds).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = Ds:lookup(Ds, Key),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
Ds:update_element(Ds, Key, {2, Value}),
update(Num - 1, Ds).
for(Num, Ds) ->
Fun =
fun({Key, Value}, Acc) ->
Value
end,
List = Ds:foldl(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
Ds:delete(Ds, Key),
delete(Num - 1, Ds).

+ 63
- 0
src/testCase/DsTest/etsSetDs.erl 查看文件

@ -0,0 +1,63 @@
-module(etsSetDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
ets:new(test, [set]).
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
Ds:insert(Ds, {Key, Value}),
insert(Num - 1, Ds).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = Ds:lookup(Ds, Key),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
Ds:update_element(Ds, Key, {2, Value}),
update(Num - 1, Ds).
for(Num, Ds) ->
Fun =
fun({Key, Value}, Acc) ->
Value
end,
List = Ds:foldl(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
Ds:delete(Ds, Key),
delete(Num - 1, Ds).

+ 57
- 0
src/testCase/DsTest/gb_setsDs.erl 查看文件

@ -0,0 +1,57 @@
-module(gb_setsDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, not_support, TimeF, TimeD}),
exit(normal).
init(_Num) ->
gb_sets:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = gb_sets:add_element(Key, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = gb_sets:is_element(Key, Ds),
read(Num - 1, Ds).
update(Num, Ds) ->
Ds.
for(Num, Ds) ->
Fun =
fun(Value, Acc) ->
Value
end,
List = gb_sets:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = gb_sets:del_element(Key, Ds),
delete(Num - 1, NewDs).

+ 65
- 0
src/testCase/DsTest/gb_treesDs.erl 查看文件

@ -0,0 +1,65 @@
-module(gb_treesDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
gb_trees:empty().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
NewDs = gb_trees:enter(Key, Value, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = gb_trees:lookup(Key, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
NewDs = gb_trees:update(Key, Value, Ds),
update(Num - 1, NewDs).
for(Num, Ds) ->
List = gb_trees:to_list(Ds),
for1(List),
Ds.
for1([]) ->
ok;
for1([H | T]) ->
for1(T).
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = gb_trees:delete_any(Key, Ds),
delete(Num - 1, NewDs).

+ 59
- 0
src/testCase/DsTest/listsDs.erl 查看文件

@ -0,0 +1,59 @@
-module(listsDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewArrR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewArrR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(NewDsU, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
[].
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
insert(Num - 1, [{Key, Value} | Ds]).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = lists:keyfind(Key, 1, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
NewDs = lists:keyreplace(Key, 1, Ds, {Key, Value}),
update(Num - 1, NewDs).
for([], Array) ->
Array;
for([H | T], Array) ->
for(T, Array).
delete(0, _List) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = lists:keydelete(Key, 1, Ds),
delete(Num - 1, NewDs).

+ 68
- 0
src/testCase/DsTest/mapsDs.erl 查看文件

@ -0,0 +1,68 @@
-module(mapsDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
maps:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
NewDs = maps:put(Key, Value, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
case Ds of
#{Key := Value} ->
Value;
_ ->
undefined
end,
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
NewDs = maps:update(Key, Value, Ds),
update(Num - 1, NewDs).
for(Num, Ds) ->
Fun =
fun(Key, Value, Acc) ->
Value
end,
List = maps:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = maps:remove(Key, Ds),
delete(Num - 1, NewDs).

+ 63
- 0
src/testCase/DsTest/orddictDs.erl 查看文件

@ -0,0 +1,63 @@
-module(orddictDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, TimeD}),
exit(normal).
init(_Num) ->
orddict:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
NewDs = orddict:store(Key, Value, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = orddict:fetch(Key, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
NewDs = orddict:store(Key, Value, Ds),
update(Num - 1, NewDs).
for(Num, Ds) ->
Fun =
fun(Key, Value, Acc) ->
Value
end,
List = orddict:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = orddict:erase(Key, Ds),
delete(Num - 1, NewDs).

+ 58
- 0
src/testCase/DsTest/ordsets.erl 查看文件

@ -0,0 +1,58 @@
-module(ordsets).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewOrdSetU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewOrdSetF = for(Num, NewOrdSetU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewOrdSetF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, not_support, TimeF, TimeD}),
exit(normal).
init(_Num) ->
ordsets:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
NewDs = ordsets:add_element(Key, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = ordsets:is_element(Key, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds.
for(Num, Ds) ->
Fun =
fun(Key, Acc) ->
Key
end,
List = ordsets:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = ordsets:del_element(Key, Ds),
delete(Num - 1, NewDs).

+ 67
- 0
src/testCase/DsTest/pdDs.erl 查看文件

@ -0,0 +1,67 @@
-module(pdDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, not_support}),
exit(normal).
init(Num) ->
undefined.
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
erlang:put(Key, Value),
insert(Num - 1, Ds).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = erlang:get(Key),
V = if Value == 1 -> 1; true -> 2 end,
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV2(Num),
erlang:put(Key, Value),
update(Num - 1, Ds).
for(Num, Ds) ->
Keylist = erlang:get(),
for1(Keylist, undefined),
Ds.
for1([], V) ->
ok;
for1([H | T], _V) ->
V = erlang:get(H),
for1(T, V).
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
erlang:erase(Key),
delete(Num - 1, Ds).

+ 49
- 0
src/testCase/DsTest/persistentTermDs.erl 查看文件

@ -0,0 +1,49 @@
-module(persistentTermDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, not_support, not_support, not_support}),
exit(normal).
init(Num) ->
undefined.
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = utTestDs:makeV(Num),
persistent_term:put(Key, Value),
insert(Num - 1, Ds).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
persistent_term:get(Key),
read(Num - 1, Ds).
update(0, Ds) ->
Ds.
for(Num, Ds) ->
Ds.
delete(0, Ds) ->
ok.

+ 57
- 0
src/testCase/DsTest/setsDs.erl 查看文件

@ -0,0 +1,57 @@
-module(setsDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, not_support, TimeF, TimeD}),
exit(normal).
init(_Num) ->
sets:new().
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = sets:add_element(Key, Ds),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = sets:is_element(Key, Ds),
read(Num - 1, Ds).
update(Num, Ds) ->
Ds.
for(Num, Ds) ->
Fun =
fun(Value, Acc) ->
Value
end,
sets:fold(Fun, [], Ds),
Ds.
delete(0, Ds) ->
ok;
delete(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = sets:del_element(Key, Ds),
delete(Num - 1, NewDs).

+ 55
- 0
src/testCase/DsTest/tupleDs.erl 查看文件

@ -0,0 +1,55 @@
-module(tupleDs).
-compile([nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-export([start/2]).
start(Num, Pid) ->
Ds = init(Num),
erlang:statistics(wall_clock),
NewDsI = insert(Num, Ds),
{_, TimeI} = erlang:statistics(wall_clock),
NewDsR = read(Num, NewDsI),
{_, TimeR} = erlang:statistics(wall_clock),
NewDsU = update(Num, NewDsR),
{_, TimeU} = erlang:statistics(wall_clock),
NewDsF = for(Num, NewDsU),
{_, TimeF} = erlang:statistics(wall_clock),
delete(Num, NewDsF),
{_, TimeD} = erlang:statistics(wall_clock),
erlang:send(Pid, {over, self(), TimeI, TimeR, TimeU, TimeF, not_support}),
exit(normal).
init(Num) ->
erlang:make_tuple(Num, undefined).
insert(0, Ds) ->
Ds;
insert(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = erlang:setelement(Num, Ds, utTestDs:makeV(Num)),
insert(Num - 1, NewDs).
read(0, Ds) ->
Ds;
read(Num, Ds) ->
Key = utTestDs:makeK(Num),
Value = erlang:element(Num, Ds),
read(Num - 1, Ds).
update(0, Ds) ->
Ds;
update(Num, Ds) ->
Key = utTestDs:makeK(Num),
NewDs = erlang:setelement(Num, Ds, utTestDs:makeV2(Num)),
update(Num - 1, NewDs).
for(0, Ds) ->
Ds;
for(Num, Ds) ->
Value = erlang:element(Num, Ds),
for(Num - 1, Ds).
delete(Num, Ds) ->
ok.

+ 73
- 0
src/testCase/DsTest/utTestDs.erl 查看文件

@ -0,0 +1,73 @@
-module(utTestDs).
-compile([export_all, nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
-define(V_NUM, [8, 16, 32, 64, 128, 256, 516, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 524288, 1048576]).
-define(DsList, [arrayDs, tupleDs, listsDs, setsDs, gb_setsDs, gb_treesDs, dictDs, etsSetDs, etsOrdDs, mapsDs, orddictDs, ordsetsDs, pdDs, atomicsDs, persistentTermDs]).
recRet(Type, Time) ->
erlang:put(Type, Time).
getRet(Type) ->
erlang:get(Type).
makeK(N) ->
case N rem 4 of
0 ->
N;
1 ->
{N, <<"test-testDs">>};
2 ->
{N, 8686};
3 ->
{N, test}
end.
makeV(N) ->
case N rem 4 of
0 ->
N;
1 ->
{N, <<"test-testDs">>};
2 ->
{N, 8787.87878, <<"test-testDs">>};
3 ->
{N, test, [list, 123, 456.789, "test"], {23231, "gggggg"}, <<"12345678901234567890">>}
end.
makeV2(N) ->
case N rem 4 of
0 ->
{N, 8787.87878, <<"test-testDs">>};
1 ->
{N, test, [list, 123, 456.789, "test"], {23231, "gggggg"}, <<"12345678901234567890">>};
2 ->
N;
3 ->
{N, <<"test-testDs">>}
end.
start() ->
%% erlang:process_flag(trap_exit, true),
io:format("Ds benchmark...~n~n" ++ "DsName V_Num insert read update for delete ~n" ++ [$= || _ <- lists:seq(1, 51)] ++ "~n", []),
runDs(?DsList, ?V_NUM).
runDs([Ds | T], VNumList) ->
runNum(VNumList, Ds),
runDs(T, VNumList);
runDs([], _VNumList) ->
ok.
runNum([Num | T], Ds) ->
runExe(Num, Ds),
runNum(T, Ds);
runNum([], _Ds) ->
ok.
runExe(Num, Ds) ->
Pid = erlang:spawn_link(Ds, start, [Num, self()]),
receive
{over, Pid, Insert, Read, Update, For, Delete} ->
io:format("~-10s ~8B ~8B ~8B ~8B ~8B ~8B~n", [Ds, Num, Insert, Read, Update, For, Delete]);
_ShutDown ->
io:format("Ds test shutDown ~p ~p~n",[Ds, Num])
end.

+ 0
- 656
src/testCase/utTestDS.erl 查看文件

@ -1,662 +1,6 @@
-module(utTestDS).
-compile([export_all, nowarn_unused_function, nowarn_unused_vars, nowarn_export_all]).
Erlang常用数据结构的内部实现和特性Erlang OTP 18.0()
Erlang虚拟机使用一个字(64/32)EtermEterm的后几位作为类型标签
list62Cons的指针
boxed对象62boxed对象的对象头Pid/Port等
immediate立即数Pid/PortAtomNIL等
Erlang类型的大框架Erlang Eterm本身只占用一个字
.
1. atom
atom用立即数表示Eterm中保存的是atom在全局atom表中的索引Erlang的atom比较和匹配像整数一样高效atom表是不回收的1024*1024Erlang虚拟机将会崩溃+t参数调整该上限
2.Pid/Port
/* erts/emulator/beam/erl_term.h
*
* Old pid layout(R9B及之前):
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |s s s|n n n n n n n n n n n n n n n|N N N N N N N N|c c|0 0|1 1|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* s : serial n到达2^15 n重新从低位开始
* n : number 15,
* c : creation
* N : node number atom表中索引
*
*
* PID layout (internal pids):
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |n n n n n n n n n n n n n n n n n n n n n n n n n n n n|0 0|1 1|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* n : number 28Pid
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Old Pid表示中(R9B及之前版本)32PidEterm立即数表示<N, n, s>
R9B之后Pid只在32位中表示本地Pid(A=0)324Tag之外的28位Pid表示Pid表示的历史原因Pid表示变成了<0, Pid低15位, Pid高13位>Pidboxed复合对象表示Pid发往其它node时Erlang会自动将为Pid加上本地节点信息boxed对象6Erlang需要维护Pid表8Pid表将占用大量内存Erlang默认可以使用18位有效位来表示Pid(262144)+P参数调节27(2^27-1)Pid表占用内存为2G
Eshell V8.1 (abort with ^G)
(n1@T4F-MBP-11)1> node().
'n1@T4F-MBP-11'
%
(n1@T4F-MBP-11)2> term_to_binary(node()).
<<131,100,0,13,110,49,64,84,52,70,45,77,66,80,45,49,49>>
(n1@T4F-MBP-11)3> self().
<0.63.0>
% term_to_binary会将A对应的节点名编码进去
(n1@T4F-MBP-11)4> term_to_binary(self()).
<<131,103,100,0,13,110,49,64,84,52,70,45,77,66,80,45,49,
49,0,0,0,63,0,0,0,0,2>>
(n1@T4F-MBP-11)5>
1
2
3
4
5
6
7
8
9
10
11
12
13
3. lists
0162Cons单元Cons是[Head|Tail]EtermHead可以是任何类型的EtermTail是列表类型的EtermL2 = [Elem|L1]ConsHead是Elem EtermTail是L1 EtermL2的Eterm指向了这个新的ConsL2即代表了这个新的列表[Elem|L2] = L1L1 Eterm指向的ConsHead部分赋给ElemTail部分赋给L2Tail本身就是个List的Etermlist是单向列表Erlang所有类型的Eterm本身只占用一个字大小list,tuple能够容纳任意类型的基础
Erlang中进程内对对象的重复引用只需占用一份对象内存(Eterm本身一个字的拷贝)
Eshell V7.0.2 (abort with ^G)
1> L1 = [1,2,3].
[1,2,3]
2> erts_debug:size(L1).
6
3> L2 = [L1,L1,L1].
[[1,2,3],[1,2,3],[1,2,3]]
4> erts_debug:size(L2). % L2对象树的大小 3*2+6
12
5> erts_debug:flat_size(L2). % 3*(2+6)
24
6> P1 = spawn(fun() -> receive L -> io:format("~p~n",[erts_debug:size(L)]) end end).
<0.45.0>
7> P1 ! L2. %
24
[[1,2,3],[1,2,3],[1,2,3]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
L1, L2的内存布局如下
4. tuple
tuple属于boxed对象的一种boxed对象都有一个对象头(header)boxed Eterm即指向这个headerheader里面包含具体的boxed对象类型tuple的header末6位为000000tuple的size
tuple实际上就是一个有头部的数组Eterm在内存中紧凑排列tuple的操作效率和数组是一致的
list和tuple是erlang中用得最多的数据结构recordmaplisttuple操作的常用函数便
// $OTP_SRC/erts/emulator/beam/bif.c
BIF_RETTYPE tuple_to_list_1(BIF_ALIST_1)
{
Uint n;
Eterm *tupleptr;
Eterm list = NIL;
Eterm* hp;
if (is_not_tuple(BIF_ARG_1)) {
BIF_ERROR(BIF_P, BADARG);
}
// tuple Eterm所指向的tuple对象头
tupleptr = tuple_val(BIF_ARG_1);
// tuple size
n = arityval(*tupleptr);
hp = HAlloc(BIF_P, 2 * n);
tupleptr++;
// list CONS的构造是倒序的
while(n--) {
// hp[0]=tupleptr[n]; hp[1] = list; list = make_list(hp);
// hp的list Eterm
list = CONS(hp, tupleptr[n], list);
hp += 2;
}
BIF_RET(list);
}
BIF_RETTYPE list_to_tuple_1(BIF_ALIST_1)
{
Eterm list = BIF_ARG_1;
Eterm* cons;
Eterm res;
Eterm* hp;
int len;
if ((len = erts_list_length(list)) < 0 || len > ERTS_MAX_TUPLE_SIZE) {
BIF_ERROR(BIF_P, BADARG);
}
// +
hp = HAlloc(BIF_P, len+1);
res = make_tuple(hp);
*hp++ = make_arityval(len);
while(is_list(list)) {
cons = list_val(list);
*hp++ = CAR(cons);
list = CDR(cons);
}
BIF_RET(res);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
listtuple中添加元素Eterm本身Erlang虚拟机会追踪这些引用
5. binary
Erlang binary用于处理字节块Erlang其它的数据结构(list,tuple,record)Eterm为单位的abc7(ETerm本身)binary为字节流提供一种操作高效
Erlang进程堆上使binary跨进程传输时的拷贝开销Erlang针对binary作出了优化binary分为小binary和大binary
heap binary
64(erl_binary.h ERL_ONHEAP_BIN_LIMIT宏)binary直接创建在进程堆上heap binaryheap binary是一个boxed对象
typedef struct erl_heap_bin {
Eterm thing_word; /* Subtag HEAP_BINARY_SUBTAG. */
Uint size; /* Binary size in bytes. */
Eterm data[1]; /* The data in the binary. */
} ErlHeapBin;
1
2
3
4
5
refc binary
64binary将创建在Erlang虚拟机全局堆上refc binary(reference-counted binary)Erlang进程共享binary本身进行引用计数追踪便GCrefc binary需要两个部分来描述refc binary数据本身和位于进程堆的binary引用(proc binary)global.h中refc binary和proc binary的关系
OffHeap()(erl_process.h struct process)off_heap字段维护链表头和所有OffHeap对象的总大小GCrefc binary只是OffHeap对象的一种
sub binary
sub binary是Erlang为了优化binary分割的(split_binary/2)Erlang变量不可变语义binary是效率比较底下的做法Erlang通过sub binary来复用原有binaryErlSubBin定义于erl_binary.hsplit_binary(ProBin, size1)ErlSubBin二元组的过程
ProBin的size可能小于refc binary的sizesize3refc binary通常会通过预分配空间的方式进行优化
sub binary只引用proc binary(orig)refc binaryrefc binary的refc字段仍然为1sub binary还有效proc binary便不会被GCrefc binary的计数也就不为0
bit string
<<2:3,3:6>>binary时<<65,1:1>>Erlang中被称为bitstringErlang的bitstring基于ErlSubBin结构实现bitsize为最后一个字节的有效位数size为有效字节数()sub bianry和bit string是同一种数据结构
binary追加构造优化
C = <<A/binary,B/binary>>binary时C(heap or refc)A和B的数据拷贝进去Erlang对binary的优化不止于此使refc binary的预留空间binary和频繁追加的效率
Bin0 = <<0>>, %% heap binary Bin0
Bin1 = <<Bin0/binary,1,2,3>>, %% refc binaryrefc binary256Bin0初始化1,2,3
Bin2 = <<Bin1/binary,4,5,6>>, %% refc binary且有预留空间 4,5,6
Bin3 = <<Bin2/binary,7,8,9>>, %% 7,8,9refc binary预留空间
Bin4 = <<Bin1/binary,17>>, %% Bin2内容Bin1拷贝到新的refc binary
{Bin4,Bin3}
% erts_get_internal_state/1binary状态
% $BEAM_SRC/erl_bif_info.c erts_debug_get_internal_state_1
f() ->
B0 = <<0>>,
erts_debug:set_internal_state(available_internal_state,true), %
f2(B0). % B0 B1为heap binary
f2(B0) ->
io:format("B0: ~p~n", [erts_debug:get_internal_state({binary_info,B0})]),
B1 = <<B0/binary, 1,2,3>>,
io:format("B1: ~p~n", [erts_debug:get_internal_state({binary_info,B1})]),
B2 = <<B1/binary, 4,5,6>>,
io:format("B2: ~p~n", [erts_debug:get_internal_state({binary_info,B2})]),
ok.
% get_internal_state({binary_info, B}):
% proc binary{refc_binary, pb_size, {binary, orig_size}, pb_flags}
% heap binaryheap_binary
B0: heap_binary
B1: {refc_binary,4,{binary,256},3}
B2: {refc_binary,7,{binary,256},3}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
binary追加实现源码位于$BEAM_SRC/erl_bits.c erts_bs_appendB1和B2本身是sub binaryProcBinrefc binary只能被一个ProcBin引用refc binary可能会在追加过程中重新分配空间ProcBin引用refc binary无法快速追踪到其所有ProcBin引用()ProcBin上的sub binary可能对refc binary覆写
sub binary才可执行快速追加(sub binary和对应ProBin flags来判定)refc binarysub binary都是指向ProcBin或heap binary的sub binary本身
binary降级
Erlang通过追加优化构造出的可追加refc binary通过空间换取了效率refc binary只能被一个proc binary引用(proc binary上的sub binary会造成覆写B1B2是sub binary而不是ProBin)ProBinrefc binary来说ProBinbinary降级refc binary降级为普通refc binary
bs_emasculate(Bin0) ->
Bin1 = <<Bin0/binary, 1, 2, 3>>,
NewP = spawn(fun() -> receive _ -> ok end end),
io:format("Bin1 info: ~p~n", [erts_debug:get_internal_state({binary_info, Bin1})]),
NewP ! Bin1,
io:format("Bin1 info: ~p~n", [erts_debug:get_internal_state({binary_info, Bin1})]),
Bin2 = <<Bin1/binary, 4, 5, 6>>, % Bin1被收缩 refc binary拷贝
io:format("Bin2 info: ~p~n", [erts_debug:get_internal_state({binary_info, Bin2})]),
Bin2.
%
117> bs_emasculate(<<0>>).
Bin1 info: {refc_binary,4,{binary,256},3}
Bin1 info: {refc_binary,4,{binary,4},0}
Bin2 info: {refc_binary,7,{binary,256},3}
<<0,1,2,3,4,5,6>>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
refc binary(refc binary会被GC?)B1的flags置0B1的sub binary在执行追加时refc binary
// ($BEAM_SRC/erl_bits.c)
void erts_emasculate_writable_binary(ProcBin* pb)
{
Binary* binp;
Uint unused;
pb->flags = 0;
binp = pb->val;
ASSERT(binp->orig_size >= pb->size);
unused = binp->orig_size - pb->size;
/* Our allocators are 8 byte aligned, i.e., shrinking with
less than 8 bytes will have no real effect */
if (unused >= 8) {
// ProBin中的有效字节数refc binary
binp = erts_bin_realloc(binp, pb->size);
pb->val = binp;
pb->bytes = (byte *) binp->orig_bytes;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Q: ProcBin B1的字段被更新了Erlang上层如何维护变量不可变语义?
A: Erlang虚拟机上层通过底层屏蔽后所能看到的不变语义Pid打包maps
hash扩展等)
GC也可能会对可追加refc binary的预留空间进行收缩(shrink)$BEAM_SRC/erl_gc.c sweep_off_heap函数
Erlang虚拟机对二进制还做了一些基于上下文的优化bin_opt_info编译选项可以打印出这些优化binary优化的更多细节Constructing and Matching Binaries
.
list和tuple之上Erlang还提供了一些其它的数据结构key/value相关的数据结构
1. record
tuplerecord filed在预编译后实际上都是通过数值下标来索引访field是O(1)
2. map
record的语法糖让我们在使用tuple时便利了不少key/value结构仍然有许多限制key只能是原子key不能动态添加或删除record变动对热更的支持很差等proplists能够一定程度地解决这种问题key的唯一
map是OTP 17boxed对象KeyKey等mongodb-erlang直接支持map
OTP17中map的内存结构为
// $OTP_SRC/erts/emulator/beam/erl_map.h
typedef struct map_s {
Eterm thing_word; // boxed对象header
Uint size; // map
Eterm keys; // keys的tuple
} map_t;
1
2
3
4
5
6
Valuemaps的get操作keys tuplekey所在下标value中取出该下标偏移对应的值O(n)maps:get源码($BEAM_SRC/erl_map.c erts_maps_get)
mapsrecord的替用Key->Value映射OTP18中maps加入了针对于big map的hash机制maps:size < MAP_SMALL_MAP_LIMIT时使flatmap结构OTP17中的结构maps:size >= MAP_SMALL_MAP_LIMIT时使hashmap结构来高效存取数据MAP_SMALL_MAP_LIMIT在erl_map.h中默认定义为32
Erlang本身的变量不可变原则mapsmapsmaps的keys和valuesmaps:update比maps:put更高效keys数量不会变keys tuplekeys tuples ETerm即可使maps时
key值时使update(:=)put(=>)
key/value对太多时
OTP18中的maps在存取大量数据时maps和dict的简单测试函数OTP17和OTP18分别运行来查看效率区别使mapsdictmongodb支持
3. array
Erlang有个叫array的结构
array下标从0开始
array有两种模式
array:set(100,value,array:new())[0,99](undefined)
array最外层被包装为一个record:
-record(array, {
size :: non_neg_integer(), %% number of defined entries
max :: non_neg_integer(), %% maximum number of entries
default, %% the default value (usually 'undefined')
elements :: elements(_) %% the tuple tree
}).
1
2
3
4
5
6
elements是一个tuple treetuple包含tuple的方式组成的树10array用其叶子节点数量代替
Eshell V7.0.2 (abort with ^G)
1> array:set(9,value,array:new()).
{array,10,10,undefined, %
{undefined,undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,value}}
% 19 9
% tuple一共有11个元素
2> array:set(19,value,array:new()).
{array,20,100,undefined,
{10,
{undefined,undefined,undefined,undefined,undefined undefined,undefined,undefined,undefined,value},
10,10,10,10,10,10,10,10,10}}
% 199
3> array:set(199,value,array:new()).
{array,200,1000,undefined,
{100,
{10,10,10,10,10,10,10,10,10,
{undefined,undefined,undefined,undefined,undefined,
undefined,undefined,undefined,undefined,value},
10},
100,100,100,100,100,100,100,100,100}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tuple tree是一颗完全十叉树array的自动扩容也是以10为基数的Index查找元素时div/rem逐级算出Index所属节点:
%% $OTP_SRC/lib/stdlib/src/array.erl
get(I, #array{size = N, max = M, elements = E, default = D})
when is_integer(I), I >= 0 ->
if I < N -> %
get_1(I, E, D);
M > 0 -> % I>=N array处于自动扩容模式 DefaultValue
D;
true -> % I>=N array为固定大小 badarg
erlang:error(badarg)
end;
get(_I, _A) ->
erlang:error(badarg).
%% The use of NODEPATTERN(S) to select the right clause is just a hack,
%% but it is the only way to get the maximum speed out of this loop
%% (using the Beam compiler in OTP 11).
% -define(NODEPATTERN(S), {_,_,_,_,_,_,_,_,_,_,S}). % NODESIZE+1 elements!
get_1(I, E=?NODEPATTERN(S), D) -> %
get_1(I rem S, element(I div S + 1, E), D);
get_1(_I, E, D) when is_integer(E) -> %
D;
get_1(I, E, _D) -> %
element(I+1, E).
set(I, Value, #array{size = N, max = M, default = D, elements = E}=A)
when is_integer(I), I >= 0 ->
if I < N ->
A#array{elements = set_1(I, E, Value, D)};
I < M -> % size, size的主要作用是让读取更加高效
%% (note that this cannot happen if M == 0, since N >= 0)
A#array{size = I+1, elements = set_1(I, E, Value, D)};
M > 0 -> %
{E1, M1} = grow(I, E, M),
A#array{size = I+1, max = M1,
elements = set_1(I, E1, Value, D)};
true ->
erlang:error(badarg)
end;
set(_I, _V, _A) ->
erlang:error(badarg).
%% See get_1/3 for details about switching and the NODEPATTERN macro.
set_1(I, E=?NODEPATTERN(S), X, D) -> %
I1 = I div S + 1,
setelement(I1, E, set_1(I rem S, element(I1, E), X, D));
set_1(I, E, X, D) when is_integer(E) -> %
expand(I, E, X, D);
set_1(I, E, X, _D) -> %
setelement(I+1, E, X).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
Erlang array和其它语言数组不一样的地方
O(1)O(log10n)
array并不自动收缩
array中的max和size字段array具体占用内存没多大关系()
array中并没有subarray之类的操作线O(n)O(n*log10n)
array中对于没有赋值的元素undefinedarray:new()使undefined和默认值undefined并无多大区别array内部来说
6.2 Is there a collection of data structures, e.g. balanced trees?
Erlang的基本组成部分
Module Description
sets sets, a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
queue double-ended queues
ets hash tables and ordered sets (trees), stored outside the process
dets on-disk hash tables
6.1
(ordset和 orddict只是有序列表On)
% Suggestion
% elments count: 0 100 | 100 - 10000 | 10000 -
% our select : list | ets | gb_tree
%% erlang各种数据结构
%%  lists maps record是erlang最为常用的数据结构lists使用方便简单maps则查询高效record则需要预定义
%% lists和maps的性能对比dictrecord操作不便则不做比较

+ 1
- 1
src/testCase/utTestMd5.erl 查看文件

@ -113,7 +113,7 @@ uuid2() ->
get_uuid() ->
<<(crypto:strong_rand_bytes(8))/bytes,
(erlang:term_to_binary(erlang:now()))/bytes>>.
(erlang:term_to_binary(erlang:timestamp()))/bytes>>.
u1(0) ->
crypto:strong_rand_bytes(16);

Loading…
取消
儲存