Guest User

Untitled

a guest
Jun 12th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 9.33 KB | None | 0 0
  1. -module(ttt).
  2. -include_lib("eunit/include/eunit.hrl").
  3.  
  4. -export([do/2,do_spl/2,do_work/4]).
  5.  
  6. -record(state,
  7.                 {
  8.                     data=[],
  9.                     x_num = 0,
  10.                     childs = dict:new(),
  11.                     count_in_batch= 10,
  12.                     responces = gb_trees:empty(),
  13.                     parent_pid = 0,
  14.                     spawn_func= fun(A,B,C,D,E) -> spawn_chld(A,B,C,D,E) end
  15.                 }).
  16.  
  17. do(L, X)->
  18.     do(L,X,[],0,length(L),[]).
  19. %   Lst = [ P || P <- L, P<X],
  20. %   Llen = length(Lst),
  21. %   FirstPartLen = Llen div 2,
  22. %   lists:append(lists:sublist(Lst, FirstPartLen),lists:reverse(lists:sublist(Lst,FirstPartLen+1,Llen-FirstPartLen))).
  23.  
  24.  
  25. do([], _, Ret, _, _, Ret2)  ->
  26.     lists:append(Ret,Ret2);
  27. do([H|T], X, Ret, Cntr, Len, Ret2) when X>H, Cntr=:=(Len div 2-1) ->
  28.     do(T,X,lists:reverse([H|Ret]),Cntr+1, Len, Ret2);
  29. do([H|T], X, Ret, Cntr, Len, Ret2) when X>H, Cntr<(Len div 2-1) ->
  30.     do(T, X, [H|Ret], Cntr+1, Len, Ret2);
  31. do([H|T], X, Ret, Cntr, Len, Ret2) when X>H, Cntr>(Len div 2-1) ->
  32.     do(T, X, Ret, Cntr+1, Len,[H|Ret2]);
  33. do([_|T],X,Ret,Cntr,Len,Ret2)->
  34.     do(T,X,Ret,Cntr,Len,Ret2).
  35.  
  36. %Removes all elements from Array for Count elements
  37. %which are greater than X
  38.  
  39. % (List, X, Count, RetArray)
  40. do_work(Arr, X, Count, RetFunc)->
  41.     RetFunc(do_p(Arr,X,Count,[])).
  42.  
  43. do_p(_,_,0,Ret) ->
  44.     lists:reverse(Ret);
  45. do_p([],_,_,Ret) ->
  46.     do_p([],0,0,Ret); %just call for done work
  47. do_p([H|T], X,  Count, Ret) when X>H ->
  48.     do_p(T, X, Count-1, [H | Ret]);
  49. do_p([_|T], X, Count, Ret) ->
  50.     do_p(T, X, Count-1, Ret).
  51.  
  52. do_spl(L,X)->
  53.     MyPid=  self(),
  54.     Pid = spawn(fun()-> process_flag(trap_exit, true), loop(#state{parent_pid=MyPid}) end),
  55.     Pid!{splitme,{L, X}},
  56.     receive
  57.         {resp, R} ->
  58.             {ok,R}
  59.         after 10000 ->
  60.             {timeout,[]}
  61.     end.
  62.  
  63. make_split(Lst, X, CountForWorker, FuncCallb)->
  64.     make_split(Lst, X, {CountForWorker,0,0}, dict:new(), FuncCallb).
  65.  
  66. make_split([], _,_,Chlds,_)->
  67.     Chlds;
  68.  
  69. make_split(T, X, {CountForWorker, 0, CurIndex}, Chlds, FuncCallb)->
  70.     NewChlds = FuncCallb(T, X, CountForWorker, Chlds, CurIndex),
  71.     make_split(T, X, {CountForWorker, CountForWorker, CurIndex}, NewChlds, FuncCallb);
  72.  
  73. make_split([_|T], X, {CountForWorker, CurCnt, CurIndex}, Chlds, FuncCallb)->
  74.     make_split(T, X, {CountForWorker, CurCnt-1, CurIndex+1}, Chlds, FuncCallb).
  75.        
  76.  
  77. spawn_chld(L, X, Cnt, Chlds, CurIndex)->
  78.     MyPid = self(),
  79.     Pid = spawn_link(?MODULE, do_work, [L, X, Cnt,fun(Ret) -> MyPid ! {done,{self(),Ret}} end]),
  80.     dict:store(Pid, {L, CurIndex}, Chlds).
  81.  
  82. %split arrays from dictionary
  83. joinResult(Dct,Ln)->
  84.     Iter = gb_trees:iterator(Dct),
  85.     joinResult(gb_trees:next(Iter),[],[],Ln div 2).
  86.  
  87. joinResult(none,Result,RResult,_)->
  88.     lists:append(Result,lists:reverse(RResult));
  89. joinResult({Key,Val,Iter}, Result, RResult, Middle) when Middle =< 0 ->
  90.     NRlst = lists:append(RResult,Val),
  91.     joinResult(gb_trees:next(Iter),Result,NRlst,Middle);
  92. joinResult({Key,Val,Iter}, Result,RResult, Middle)->
  93.     NMiddle = Middle-length(Val),
  94.     if
  95.         NMiddle >= 0 ->
  96.                 Nlst = lists:append(Result,Val),
  97.                 joinResult(gb_trees:next(Iter),Nlst,RResult,NMiddle);
  98.         true ->
  99.                 {P1,P2} = lists:split(0-NMiddle,Val),
  100.                 Nlst = lists:append(Result,P1),
  101.                 NRlst = lists:append(RResult,P2),
  102.                 joinResult(gb_trees:next(Iter),Nlst,NRlst,-1)
  103.     end.
  104.  
  105. loop(State)->
  106.     receive
  107.         {splitme,{L,X}} ->
  108.             NewState  = have_new_work(L,X,State, State#state.spawn_func),
  109.             loop(NewState);
  110.            
  111.         {done, {Pid,L}} ->
  112.             NewState = child_done(Pid, State, L),
  113.             DSize =dict:size(NewState#state.childs),
  114.             if
  115.             DSize > 0 ->
  116.                 loop(NewState);
  117.             true->
  118.                 Resps = NewState#state.responces,
  119.                 NewState#state.parent_pid ! {resp, joinResult(Resps,length(State#state.data))}
  120.             end;
  121.            
  122.         {'EXIT', Pid, Reason} ->
  123.             case Reason of
  124.                 normal -> loop(State);
  125.                 _ ->
  126.                     NewState = child_dyed(Pid, State, fun(A,B,C,D,E) -> spawn_chld(A,B,C,D,E) end),
  127.                     loop(NewState)
  128.             end
  129.     end.
  130.  
  131. %Got list L, Number X
  132. %State is current state
  133. %callb - function for spawning child
  134. %spawn workers and change state
  135. have_new_work(L, X, State, Callb)->
  136.     New_Chlds = make_split(L, X, State#state.count_in_batch, Callb),
  137.     State#state{childs=New_Chlds,x_num=X,data=L}.
  138.  
  139. child_done(Pid, State, L)->
  140.     {_, Indx} = dict:fetch(Pid, State#state.childs),       
  141.     New_Resps = gb_trees:enter(Indx, L, State#state.responces),     %save result
  142.     New_Chlds = dict:erase(Pid, State#state.childs),        %remove unneeded pid
  143.     State#state{childs=New_Chlds,responces=New_Resps}.
  144.  
  145. child_dyed(Pid, State, CallBack) ->
  146.     {Lst, Indx} = dict:fetch(Pid,State#state.childs),       %get dyed pid work
  147.     %spawn next worker
  148.     NewChlds = CallBack(Lst, State#state.x_num, State#state.count_in_batch, State#state.childs, Indx), 
  149.     State#state{childs=dict:erase(Pid,NewChlds)}.
  150.  
  151.  
  152.  
  153. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  154. %                                   TESTS
  155. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  156.  
  157. do_test()->
  158.     ?assertEqual([2,3,5,4],do([2,3,4,5],10)),
  159.     ?assertEqual([],do([2],1)),
  160.     ?assertEqual([2],do([2],5)),
  161.     ?assertEqual([2,5,3],do([2,3,5],10)),
  162.     ?assertEqual([2,1,3],do([5,2,1,3],5)),
  163.     ?assertEqual([3,2,4,3],do([3,2,5,3,4],5)).
  164.  
  165. do_work_test()->
  166.     %only ensure that callback is called
  167.     ?assertEqual([2,3,1],do_work([2,4,3,1],4,4,fun(Ret)-> Ret end)).
  168.  
  169. do_p_test()->
  170.     ?assertEqual([],do_p([2,3,4,5],1,10,[])),   %empty returned
  171.     ?assertEqual([2,3],do_p([2,3,4,5],4,2,[])), %only 2 values
  172.     ?assertEqual([2,3,1],do_p([2,4,3,1],4,4,[])), %3 values with gaps and strong check that 4>4
  173.     ?assertEqual([1],do_p([1,3,4,5],2,1,[])), %only one, and ok
  174.     ?assertEqual([],do_p([2,3,4,5],2,1,[])), %only one and strong check 2>2
  175.     ?assertEqual([1],do_p([1,3,4,5],2,1,[])), % check 2>1
  176.     LSEq=lists:seq(10,100000,1),
  177.     ?assertEqual(LSEq,do_p(LSEq,1000000+1,100000,[])). % check 2>1
  178.  
  179. test_callb_func([H|T], X, Cnt, Chlds, CurIndex)->
  180.     dict:store(CurIndex,{H, X, Cnt},Chlds).
  181.  
  182. make_split_test_check(X,_,_,_) when X<0->
  183.     ok;
  184. make_split_test_check(0,_,_,_)->
  185.     ok;
  186. make_split_test_check(Cnt,Dict,M,{S,F})->
  187.     io:format("~p ~n",[Cnt]),
  188.     ?assertEqual({Cnt, S , F}, dict:fetch(Cnt - 1 ,Dict)),
  189.     make_split_test_check(Cnt-M,Dict,M,{S,F}).
  190. make_split_test()->
  191.     Ret  = make_split([1,2,3,4,5],10,1,fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end ),
  192.     ?assertEqual(5,dict:size(Ret)),
  193.     make_split_test_check(5,Ret,1,{10,1}),
  194.  
  195.     Ret2  = make_split([1,2,3,4,5],10,2,fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end ),
  196.     ?assertEqual(3,dict:size(Ret2)),
  197.     ?assertEqual({1, 10, 2}, dict:fetch(0,Ret2)),
  198.     ?assertEqual({3, 10, 2}, dict:fetch(2,Ret2)),
  199.     ?assertEqual({5, 10, 2}, dict:fetch(4,Ret2)),
  200.  
  201.     Ret3  = make_split([1,2],10,20,fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end ),
  202.     ?assertEqual(1,dict:size(Ret3)),
  203.     ?assertEqual({1, 10, 20}, dict:fetch(0,Ret3)).
  204.  
  205. make_split2_test()->
  206.     LSEq=lists:seq(1,100,1),
  207.     Ret4  = make_split(LSEq,1000000000,10,fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end ),
  208.     io:format("~p ~n",[dict:fetch_keys(Ret4)]),
  209.     make_split_test_check(101-10,Ret4,10,{1000000000,10}).
  210.  
  211. joinResult_test()->
  212.     Dct4 = gb_trees:empty(),
  213.     Dct3 = gb_trees:enter(1,[2,3],Dct4),
  214.     Dct2 = gb_trees:enter(2,[4],Dct3),
  215.     Dct = gb_trees:enter(3,[5],Dct2),
  216.     ?assertEqual([2,3,5,4],joinResult(Dct,4)).
  217.  
  218. joinResult2_test()->
  219.     Dct4 = gb_trees:empty(),
  220.     Dct3 = gb_trees:enter(3,[5],Dct4),
  221.     Dct2 = gb_trees:enter(1,[2,3],Dct3),
  222.     Dct = gb_trees:enter(2,[4],Dct2),
  223.     ?assertEqual([2,3,5,4],joinResult(Dct,4)).
  224.  
  225. joinResult3_test()->
  226.     Dct4 = gb_trees:empty(),
  227.     Dct3 = gb_trees:enter(3,[5],Dct4),
  228.     Dct2 = gb_trees:enter(1,[2,3],Dct3),
  229.     Dct1 = gb_trees:enter(4,[6],Dct2),
  230.     Dct = gb_trees:enter(2,[4],Dct1),
  231.     ?assertEqual([2,3,6,5,4],joinResult(Dct,5)).
  232.  
  233.     %have_new_work(L, X, State, Callb)->
  234. have_new_work_test()->
  235.     State = have_new_work([1,2,3,4,5],10, #state{count_in_batch=2},fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end),
  236.     Ret2 = State#state.childs,
  237.     ?assertEqual(10,State#state.x_num),
  238.     ?assertEqual({1, 10, 2}, dict:fetch(0,Ret2)),
  239.     ?assertEqual({3, 10, 2}, dict:fetch(2,Ret2)),
  240.     ?assertEqual({5, 10, 2}, dict:fetch(4,Ret2)).
  241.  
  242. child_done_test()->
  243.     Dict2 = dict:new(),
  244.     Dict = dict:store(1,{[2,3],5},Dict2),
  245.     #state{childs=Childs,responces=Responces}= child_done(1,#state{childs=Dict},[1,20,40]),
  246.     ?assertEqual([1,20,40],gb_trees:get(5,Responces)),
  247.     ?assertEqual(0,dict:size(Childs)).
  248.  
  249. child_dyed_test()->
  250.     Dict2 = dict:new(),
  251.     Dict = dict:store(1,{[2,3],5},Dict2),
  252.     #state{childs=Childs} = child_dyed(1,#state{childs=Dict},fun(A,B,C,D,E) -> test_callb_func(A,B,C,D,E) end),
  253.     ?assertEqual(1,dict:size(Childs)),
  254.     ?assertEqual({2,0,10},dict:fetch(5,Childs)).
  255.  
  256. spawn_chld_TST(L, X, Cnt, Chlds, CurIndex)->
  257.     MyPid = self(),
  258.     Rnd = random:uniform(10),
  259.     if
  260.         Rnd>5 -> Pid = spawn_link(?MODULE, do_work, [L, X, Cnt,fun(Ret) -> MyPid ! {done,{self(),Ret}} end]);
  261.         true -> Pid = spawn_link(fun() ->  exit(tada) end)
  262.     end,
  263.     dict:store(Pid, {L, CurIndex}, Chlds).
  264.  
  265. do_spl_fake(L,X)->
  266.     MyPid=  self(),
  267.     Pid = spawn(fun()->
  268.                     process_flag(trap_exit, true),
  269.                     loop(#state{ parent_pid=MyPid,
  270.                                 spawn_func=fun(A,B,C,D,E) -> spawn_chld_TST(A,B,C,D,E) end
  271.                                 }
  272.                         )
  273.                 end),
  274.     Pid!{splitme,{L, X}},
  275.     receive
  276.         {resp, R} ->
  277.             {ok,R}
  278.         after 1000 ->
  279.             {timeout,[]}
  280.     end.
  281.  
  282. do_spl_test()->
  283.     ?assertEqual({ok,[1,2,3]},do_spl([1,2,3],5)),
  284.     ?assertEqual({ok,[1,2,3]},do_spl_fake([1,2,3],5)),
  285.     ThLst = lists:seq(10,50,1),
  286.     {ok,Out} = do_spl_fake(ThLst,100000+1),
  287.     io:format("~p ~n",[Out]),
  288.     ?assertEqual(do(ThLst,10000000000),Out).
Add Comment
Please, Sign In to add comment