方法2 在我的开源项目里面实现了,它是以gen_server
源码
方法 2 更简单的方案
- 初始化
1.1. 设定区间左右边界 RangeStart = 10000, RangeLen = 9999
1.2. 设置一个空有序集合 accountSet (可调整左右边界、写入磁盘) - 随机取出一个
- 如果 accountSet 为空,重新偏移一个accountSet,继续取
方法 1
- 初始化
1.1. 设定区间左右边界 RangeStart = 10000, RangeLen = 999999
1.2. 设定一个初始范围 Range 比如 [RangeStart, RangeStart+RangeLen),
1.3. 设置一个空有序集合 accountSet (可调整左右边界、写入磁盘) - 按Range范围生产一个随机数,判断是否再 accountSet 中
2.1. 如果存在,重新生成随机数
2.2. 如果不存在写入 accountSet - 检查accountSet
3.1.1 判断 accountSet 左侧连续元素的长度 leftInt(该算法如何时间)
3.1.2 如果 leftInt > 3,删除accountSet最左侧连续的元素,并且调整 Range 左边界,
3.2.1 判断 accountSet 右侧连续元素的长度 RightInt
3.2.2 如果 RightInt > 3 ,删除accountSet最右侧连续的元素,并且调整 Range 右边界
3.3 accountSet 总是再 Range 范围内收敛,直到空为止 - 如果accountSet为空
4.1 RangeStart 设置为 RangeStart2 = RangeStart + RangeLen + 1,
4.2 新的Range有边界自然为 RangeStart2 + RangeLen - 已新的Range范围生产一个随机数,重复步骤2 3 4
Min1 = 1, Max1 = 3.
Min2 = Max1+1, Max2=2*Max1.
Min3=Max2+1,Max3=3*Max1.
Min4=Max3+1,Max4=4*Max1.
[Min1,Max1,Min2,Max2,Min3,Max3,Min4,Max4].
account_server.erl
-module(account_server).
-behaviour(gen_server).
-include("common.hrl").
%% API.
-export([start_link/0]).
%% gen_server.
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).
%%
-export([allocate/0]).
-record(state, {
start = 0, len = 10, l = []
}).
%% API.
-spec start_link() -> {ok, pid()}.
start_link() ->
Start = start_account(),
gen_server:start_link({local, ?MODULE}, ?MODULE, [Start, 1000], []).
%% gen_server.
init([Start, Len]) ->
L = create_rand_list(Start, Len),
State = #state{start = Start , len = Len, l = L},
?LOG([?MODULE, init, State]),
{ok, State}.
%% 同步调用
% gen_server:call(account_server, allocate).
handle_call(allocate, _From, State) ->
[Account|Tail] = State#state.l,
% ?LOG([handle_call, allocate, From, State]),
case Tail of
[] ->
Start = State#state.start + State#state.len + 1,
L = create_rand_list(Start, State#state.len),
State2 = State#state{start = Start, l = L},
{reply, Account, State2};
_ ->
State2 = State#state{l=Tail},
{reply, Account, State2}
end;
handle_call(_Request, _From, State) ->
{reply, ignored, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
allocate() ->
gen_server:call(?MODULE, allocate).
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
-spec create_rand_list(Start::integer(), Len::integer()) -> list().
create_rand_list(Start, Len) ->
L = lists:seq(Start, Start + Len),
[X||{_, X} <- lists:sort([{rand:uniform(), N} || N <- L])].
-spec start_account() -> integer().
start_account() ->
Sql = <<"SELECT max(CONVERT(account, UNSIGNED INTEGER)) as max FROM `user`">>,
case mysql_pool:query(Sql) of
{ok, _,[[Start]]} ->
Start;
_ ->
50000
end.