poolboy线程池

常规操作:

try
        poolboy:transaction(Pool, fun(Worker) ->
            erlang:apply(Module, Function, [Worker | ArgRest])
        end, infinity)
    catch Class:Reason when Retries =< 0 ->
        erlang:raise(Class, Reason, erlang:get_stacktrace());
    Class:Reason ->
        lager:warning("~p retries for: Class = ~p, Reason = ~p~nMFA = ~p"
            , [?MODULE, Class, Reason, {Module, Function, Arguments}]),
        timer:sleep(Cooldown),
        wrap_retries(Module, Function, Arguments, Retries - 1, Cooldown)
    end.

transaction中是一套完整的线程池分配流程,源代码如下:

-spec transaction(Pool :: pool(), Fun :: fun((Worker :: pid()) -> any()),
    Timeout :: timeout()) -> any().
transaction(Pool, Fun, Timeout) ->
    Worker = poolboy:checkout(Pool, true, Timeout),
    try
        Fun(Worker)
    after
        ok = poolboy:checkin(Pool, Worker)
    end.

通过checkout取出pool内的线程,如果当前无线程分配,则进入等待

进入checkout函数内部

-spec checkout(Pool :: pool(), Block :: boolean(), Timeout :: timeout())
    -> pid() | full.
checkout(Pool, Block, Timeout) ->
    CRef = make_ref(),
    try
        gen_server:call(Pool, {checkout, CRef, Block}, Timeout)
    catch
        Class:Reason ->
            gen_server:cast(Pool, {cancel_waiting, CRef}),
            erlang:raise(Class, Reason, erlang:get_stacktrace())
    end.

在checkout中,先获取了一个唯一引用,同步调用线程池中的checkout方法

handle_call({checkout, CRef, Block}, {FromPid, _} = From, State) ->
    #state{supervisor = Sup,
           workers = Workers,
           monitors = Monitors,
           overflow = Overflow,
           max_overflow = MaxOverflow} = State,
    case Workers of
        [Pid | Left] ->
            MRef = erlang:monitor(process, FromPid),
            true = ets:insert(Monitors, {Pid, CRef, MRef}),
            {reply, Pid, State#state{workers = Left}};
        [] when MaxOverflow > 0, Overflow < MaxOverflow ->
            {Pid, MRef} = new_worker(Sup, FromPid),
            true = ets:insert(Monitors, {Pid, CRef, MRef}),
            {reply, Pid, State#state{overflow = Overflow + 1}};
        [] when Block =:= false ->
            {reply, full, State};
        [] ->
            MRef = erlang:monitor(process, FromPid),
            Waiting = queue:in({From, CRef, MRef}, State#state.waiting),
            {noreply, State#state{waiting = Waiting}}
    end;

存在多种情况,

1.已有worker,那么重新写入监督关系

2.无worker,但是进程池未溢出,那么建立新worker,将新的监督关系写入ets表

3.无worker,block置为false,表示不等待的情况,那么返回进程池已满

4.无worker,block置为true,那么请求进入队列,等待进程池空闲

checkout之后,返回一个空闲的worker进程,通过fun函数执行相关操作

执行完成后,通过checkin操作将worker进程返回给进程池

handle_cast({checkin, Pid}, State = #state{monitors = Monitors}) ->
    case ets:lookup(Monitors, Pid) of
        [{Pid, _, MRef}] ->
            true = erlang:demonitor(MRef),
            true = ets:delete(Monitors, Pid),
            NewState = handle_checkin(Pid, State),
            {noreply, NewState};
        [] ->
            {noreply, State}
    end;

在checkin操作中,解除了监督关系erlang:demonitor(MRef),删除了ets表中的监督关联

最后执行handle_checkin函数检测队列中是否存在等待队列

handle_checkin(Pid, State) ->
    #state{supervisor = Sup,
           waiting = Waiting,
           monitors = Monitors,
           overflow = Overflow,
           strategy = Strategy} = State,
    case queue:out(Waiting) of
        {{value, {From, CRef, MRef}}, Left} ->
            true = ets:insert(Monitors, {Pid, CRef, MRef}),
            gen_server:reply(From, Pid),
            State#state{waiting = Left};
        {empty, Empty} when Overflow > 0 ->
            ok = dismiss_worker(Sup, Pid),
            State#state{waiting = Empty, overflow = Overflow - 1};
        {empty, Empty} ->
            Workers = case Strategy of
                lifo -> [Pid | State#state.workers];
                fifo -> State#state.workers ++ [Pid]
            end,
            State#state{workers = Workers, waiting = Empty, overflow = 0}
    end.

若存在等待队列,则重新建立新的监督关系。否则,更新进程池状态,等待状态置空。

以上,进程池分配操作完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值