基于erlang gen_server 的异步特定范围随机分配账户的机制

方法2 在我的开源项目里面实现了,它是以gen_server
源码

方法 2 更简单的方案

  1. 初始化
    1.1. 设定区间左右边界 RangeStart = 10000, RangeLen = 9999
    1.2. 设置一个空有序集合 accountSet (可调整左右边界、写入磁盘)
  2. 随机取出一个
  3. 如果 accountSet 为空,重新偏移一个accountSet,继续取

方法 1

  1. 初始化
    1.1. 设定区间左右边界 RangeStart = 10000, RangeLen = 999999
    1.2. 设定一个初始范围 Range 比如 [RangeStart, RangeStart+RangeLen),
    1.3. 设置一个空有序集合 accountSet (可调整左右边界、写入磁盘)
  2. 按Range范围生产一个随机数,判断是否再 accountSet 中
    2.1. 如果存在,重新生成随机数
    2.2. 如果不存在写入 accountSet
  3. 检查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 范围内收敛,直到空为止
  4. 如果accountSet为空
    4.1 RangeStart 设置为 RangeStart2 = RangeStart + RangeLen + 1,
    4.2 新的Range有边界自然为 RangeStart2 + RangeLen
  5. 已新的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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值