Skip to content

Instantly share code, notes, and snippets.

@roowe
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roowe/140bbe75d77a53aa2620 to your computer and use it in GitHub Desktop.
Save roowe/140bbe75d77a53aa2620 to your computer and use it in GitHub Desktop.
%% 本数据结构大概目的,维护大规模数据选取小范围来随机,并定长维护,剔除老数据
-module(lists_rand).
-export([new/0, cur/1, in/2]).
-define(SIZE, 10000).
-define(CHOOSE_COUNT, 5).
-record(list_rand,{
max_size = ?SIZE,
size = 0,
every_count = ?CHOOSE_COUNT,
all_list = queue:new(),
rest_list = []
}).
new() ->
#list_rand{}.
cur(#list_rand{
all_list = Q,
rest_list = []
} = ListRand) ->
cur(ListRand#list_rand{
rest_list = queue:to_list(Q)
});
cur(#list_rand{
every_count = EveryCount,
rest_list = RestList
} = ListRand) ->
{OutList, NewRestList} = ds_misc:split(EveryCount, RestList),
{OutList, ListRand#list_rand{
rest_list = NewRestList
}}.
in(X, #list_rand{
size = Size,
all_list = Q
} = ListRand) ->
out(ListRand#list_rand{
size = Size + 1,
all_list = queue:in(X, Q)
}).
out(#list_rand{
max_size = MaxSize,
size = Size,
all_list = Q
} = ListRand)
when Size > MaxSize ->
out(ListRand#list_rand{
size = Size - 1,
all_list = element(2, queue:out(Q))
});
out(ListRand) ->
ListRand.
test() ->
ListRand = #list_rand{
max_size = 50,
every_count = 10
},
ListRand1 = lists:foldl(fun(N, AccListRand) ->
in(N, AccListRand)
end, ListRand, lists:seq(1,50)),
ListRand2 = lists:foldl(fun(N, AccListRand) ->
{OutList, NewListRand} = cur(AccListRand),
io:format("~p ~w~n", [N, OutList]),
NewListRand
end, ListRand1, lists:seq(1,6)),
ListRand3 = lists:foldl(fun(N, AccListRand) ->
in(N, AccListRand)
end, ListRand2, lists:seq(100,150)),
ListRand4 = lists:foldl(fun(N, AccListRand) ->
{OutList, NewListRand} = cur(AccListRand),
io:format("~p ~w~n", [N, OutList]),
NewListRand
end, ListRand3, lists:seq(1,6)),
ok.
%% (roowe@127.0.0.1)26> lists_rand:test().
%% 1 [10,9,8,7,6,5,4,3,2,1]
%% 2 [20,19,18,17,16,15,14,13,12,11]
%% 3 [30,29,28,27,26,25,24,23,22,21]
%% 4 [40,39,38,37,36,35,34,33,32,31]
%% 5 [50,49,48,47,46,45,44,43,42,41]
%% 6 [10,9,8,7,6,5,4,3,2,1]
%% 1 [20,19,18,17,16,15,14,13,12,11]
%% 2 [30,29,28,27,26,25,24,23,22,21]
%% 3 [40,39,38,37,36,35,34,33,32,31]
%% 4 [50,49,48,47,46,45,44,43,42,41]
%% 5 [110,109,108,107,106,105,104,103,102,101]
%% 6 [120,119,118,117,116,115,114,113,112,111]
%%%-------------------------------------------------------------------
%%% @author Roowe <bestluoliwe@gmail.com>
%%% @copyright (C) 2014, Roowe
%%% @doc
%%%
%%% @end
%%% Created : 23 Jul 2014 by Roowe <bestluoliwe@gmail.com>
%%%-------------------------------------------------------------------
-module(mod_match_league_recommened).
-behaviour(gen_server).
%% API
-export([start_link/0]).
-export([sign_up/2, recommended/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-include("common.hrl").
-include("define_mnesia.hrl").
-define(SERVER, ?MODULE).
-record(state, {}).
%%%===================================================================
%%% API
%%%===================================================================
sign_up(Ability, PlayerId) ->
gen_server:cast(?MODULE, {sign_up, Ability, PlayerId}).
recommended(Ability, PlayerId) ->
gen_server:call(?MODULE, {recommended, Ability, PlayerId}).
test() ->
Fun =
fun() ->
mod_match_league_recommened:recommended(rand_misc:rand(100), 0),
ok
%% [mod_match_league_recommened:recommended(Ability, 0) || Ability <- lists:seq(1,100)],
%% ok
end,
Before = os:timestamp(),
PidMRefs = [spawn_monitor(Fun) || _ <- lists:seq(1,3000)],
[receive
{'DOWN', MRef, process, _, normal} -> ok;
{'DOWN', MRef, process, _, Reason} -> exit(Reason)
end || {_Pid, MRef} <- PidMRefs],
After = os:timestamp(),
Times = timer:now_diff(After, Before),
io:format("~p: ~p microseconds~n", [?MODULE, Times]),
ok.
test2() ->
Data = lists:foldl(fun(N, Acc) ->
case ets_cache:get(key(N)) of
[] ->
Acc;
ListRand ->
[{N, ListRand}|Acc]
end
end, [], lists:seq(1,100)),
?DEBUG("Data ~p~n", [length(Data)]).
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
process_flag(trap_exit, true),
case hdb:dirty_read(server_data, {?MODULE, node()}) of
[] ->
ignore;
#server_data{
v = Data
} ->
?DEBUG("Data ~p~n", [length(Data)]),
[ets_cache:set(key(Ability), ListRand) || {Ability, ListRand} <- Data]
end,
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call({recommended, Ability, PlayerId}, _From, State) ->
MinAbility = erlang:max(1, Ability-10),
MaxAbility = erlang:min(100, Ability+10),
RandList =
lists:foldl(fun(N, Acc) ->
Key = key(N),
case ets_cache:get(Key) of
[] ->
Acc;
ListRand ->
{OutList, NewListRand} = lists_rand:cur(ListRand),
ets_cache:set(Key, NewListRand),
OutList ++ Acc
end
end, [], lists:seq(MinAbility, MaxAbility)),
List = rand_misc:rand_n(5, lists:delete(PlayerId, RandList)),
{reply, List, State};
handle_call(_Request, _From, State) ->
?WARNING_MSG("unknow request ~p~n", [_Request]),
Reply = ok,
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast({sign_up, Ability, PlayerId}, State) ->
Key = key(Ability),
case ets_cache:get(Key) of
[] ->
ListRand = lists_rand:new();
ListRand ->
ignore
end,
NewListRand = lists_rand:in(PlayerId, ListRand),
ets_cache:set(Key, NewListRand),
{noreply, State};
handle_cast(_Msg, State) ->
?WARNING_MSG("unknow msg ~p~n", [_Msg]),
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info({'EXIT', Pid, Reason}, State) ->
?DEBUG("Pid ~p, Reason ~p~n", [Pid, Reason]),
{stop, Reason, State};
handle_info(_Info, State) ->
?WARNING_MSG("unknow info ~p~n", [_Info]),
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(Reason, _State) ->
?DEBUG("Reason ~p~n", [Reason]),
Data = lists:foldl(fun(N, Acc) ->
case ets_cache:get(key(N)) of
[] ->
Acc;
ListRand ->
[{N, ListRand}|Acc]
end
end, [], lists:seq(1,100)),
?DEBUG("Data ~p~n", [length(Data)]),
hdb:dirty_write(server_data, #server_data{
k = {?MODULE, node()},
v = Data
}),
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================
key(Ability) ->
{?MODULE, Ability}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment