erlang的实现一个简单的进程池。

erlang进程是非常轻量级的,这个进程池的主要目的是用一种通用的方式去管理和限制系统中运行的资源占用。当运行的工作者进程数量达到上限,进程池还可以把任务放到队列中,只要进程资源被释放,排队的任务就能获得运行,否则任务只能阻塞。

这是进程池的监督树

ppool_supersup监督着所有的进程池。一个进程池由ppool_sup、ppool_serv和worker_sup监督的工作者进程池组成。ppool_serv提供对外的进程池调用api,ppool_sup负责监督单个进程池。

下面是实现代码。

%% ppool_supersup
-module(ppool_supersup).
-behavior(supervisor).
-export([start_link/0, stop/0, start_pool/3, stop_pool/1]).
-export([init/1]). start_link() ->
supervisor:start_link({local, ppool}, ?MODULE, []). stop() ->
case whereis(ppool) of
P when is_pid(P) ->
exit(P, kill);
_ ->
ok
end. init([]) ->
MaxRestart = 6,
MaxTime = 3600,
{ok, {{one_for_one, MaxRestart, MaxTime}, []}}. start_pool(Name, Limit, MFA) ->
%%每个进程池的最大终止时间设置为10500,这个值并没有什么特殊意义,只是保证足够大,所有子进程都有足够的时间终止。如果实在不知道设置为多大,可以试试infinity。
ChildSpec = {Name,
{ppool_sup, start_link, [Name, Limit, MFA]},
permanent, 10500, supervisor, [ppool_sup]},
supervisor:start_child(ppool, ChildSpec). stop_pool(Name) ->
supervisor:terminate_child(ppool, Name),
supervisor:delete_child(ppool, Name).
%% ppool_sup
-module(ppool_sup).
-export([start_link/3, init/1]).
-behavior(supervisor). start_link(Name, Limit, MFA) ->
supervisor:start_link(?MODULE, {Name, Limit, MFA}). init({Name, Limit, MFA}) ->
MaxRestart = 1,
MaxTime = 3600,
{ok, {{one_for_all, MaxRestart, MaxTime},
[{serv,
{ppool_serv, start_link, [Name, Limit, self(), MFA]},
permanent,
5000,
worker,
[ppool_serv]}]}}.
%% ppool_worker_sup
-module(ppool_worker_sup).
-export([start_link/1, init/1]).
-behavior(supervisor). start_link(MFA = {_, _, _}) ->
supervisor:start_link(?MODULE, MFA). init({M, F, A}) ->
MaxRestart = 5,
MaxTime = 3600,
{ok, {{simple_one_for_one, MaxRestart, MaxTime},
[{ppool_worker,
{M, F, A},
temporary, 5000, worker, [M]}]}}.

ppool_serv是最复杂的一个模块了。因为ppool_serv对外提供接口,它需要能联系到worker_sup。如果由ppool_sup同时启动ppool_serv和worker_sup,存在乱序的风险,除非都注册进程名。但erlang中对于原子的使用一定要慎重,能少用就少用。所以在这儿,由ppool_serv动态添加worker_sup到ppool_sup。

ppool_serv提供了三种添加任务的方式:

  • 如果进程池中有空间,立刻运行;如果已满,给出无法运行的指示。
  • 如果进程池中有空间,立刻运行;如果已满,调用者进程阻塞等待,任务入队列。
  • 如果进程池中有空间,立刻运行;如果已满,任务入队列,调用者进程不阻塞。
%% ppool_serv
-module(ppool_serv).
-behavior(gen_server).
-export([start/4, start_link/4, run/2, sync_queue/2, async_queue/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). -define(SPEC(MFA),
{worker_sup,
{ppool_worker_sup, start_link, [MFA]},
permanent,
10000,
supervisor,
[ppool_woker_sup]}). -record(state, {limit = 0,
sup,
refs,
queue = queue:new()}). start(Name, Limit, Sup, MFA) when is_atom(Name), is_integer(Limit) ->
gen_server:start({local, Name}, ?MODULE, {Limit, MFA, Sup}, []). start_link(Name, Limit, Sup, MFA) when is_atom(Name), is_integer(Limit) ->
gen_server:start_link({local, Name}, ?MODULE, {Limit, MFA, Sup}, []). run(Name, Args) ->
gen_server:call(Name, {run, Args}). sync_queue(Name, Args) ->
gen_server:call(Name, {sync, Args}, infinity). async_queue(Name, Args) ->
gen_server:cast(Name, {async, Args}). stop(Name) ->
gen_server:call(Name, stop). init({Limit, MFA, Sup}) ->
self() ! {start_worker_supervisor, Sup, MFA},
{ok, #state{limit = Limit, refs = gb_sets:empty()}}. handle_info({'DOWN', Ref, process, _Pid, _}, S = #state{refs = Refs}) ->
case gb_sets:is_element(Ref, Refs) of
true ->
handle_down_worker(Ref, S);
false ->
{noreply, S}
end;
handle_info({start_worker_supervisor, Sup, MFA}, S = #state{}) ->
{ok, Pid} = supervisor:start_child(Sup, ?SPEC(MFA)),
link(Pid),
{noreply, S#state{sup = Pid}};
handle_info(_Msg, State) ->
{noreply, State}. handle_call({run, Args}, _From, S = #state{limit = N, sup = Sup, refs = R}) when N > 0 ->
{ok, Pid} = supervisor:start_child(Sup, Args),
Ref = erlang:monitor(process, Pid),
{reply, {ok, Pid}, S#state{limit = N - 1, refs = gb_sets:add(Ref, R)}};
handle_call({run, _Args}, _From, S = #state{limit = N}) when N =< 0 ->
{reply, noalloc, S};
handle_call({sync, Args}, _From, S = #state{limit=N, sup=Sup, refs=R}) when N > 0 ->
{ok, Pid} = supervisor:start_child(Sup, Args),
Ref = erlang:monitor(process, Pid),
{reply, {ok,Pid}, S#state{limit=N-1, refs=gb_sets:add(Ref,R)}};
handle_call({sync, Args}, From, S = #state{queue=Q}) ->
{noreply, S#state{queue=queue:in({From, Args}, Q)}};
handle_call(stop, _From, State) ->
{stop, normal, ok, State};
handle_call(_Msg, _From, State) ->
{noreply, State}. handle_cast({async, Args}, S=#state{limit=N, sup=Sup, refs=R}) when N > 0 ->
{ok, Pid} = supervisor:start_child(Sup, Args),
Ref = erlang:monitor(process, Pid),
{noreply, S#state{limit=N-1, refs=gb_sets:add(Ref,R)}};
handle_cast({async, Args}, S=#state{limit=N, queue=Q}) when N =< 0 ->
{noreply, S#state{queue=queue:in(Args,Q)}};
handle_cast(_Msg, State) ->
{noreply, State}. code_change(_OldVsn, State, _Extra) ->
{ok, State}. terminate(_Reason, _State) ->
ok. handle_down_worker(Ref, S = #state{limit = L, sup = Sup, refs = Refs}) ->
case queue:out(S#state.queue) of
{{value, {From, Args}}, Q} ->
{ok, Pid} = supervisor:start_child(Sup, Args),
NewRef = erlang:monitor(process, Pid),
NewRefs = gb_sets:insert(NewRef, gb_sets:delete(Ref, Refs)),
gen_server:reply(From, {ok, Pid}),
{noreply, S#state{refs = NewRefs, queue = Q}};
{{value, Args}, Q} ->
{ok, Pid} = supervisor:start_child(Sup, Args),
NewRef = erlang:monitor(process, Pid),
NewRefs = gb_sets:insert(NewRef, gb_sets:delete(Ref, Refs)),
{noreply, S#state{refs = NewRefs, queue = Q}};
{empty, _} ->
{noreply, S#state{limit = L + 1, refs = gb_sets:delete(Ref, Refs)}}
end.

摘自《learn you some Erlang for great good》

  

erlang实现一个进程池 pool的更多相关文章

  1. [转]Python多进程并发操作中进程池Pool的应用

    Pool类 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量的时间.如果操作的对象数目不大时,还可以直接使用Process类动态的生成多个进程,十 ...

  2. Python多进程并发操作中进程池Pool的应用

    Pool类 在使用Python进行系统管理时,特别是同时操作多个文件目录或者远程控制多台主机,并行操作可以节约大量的时间.如果操作的对象数目不大时,还可以直接使用Process类动态的生成多个进程,十 ...

  3. python 使用进程池Pool进行并发编程

    进程池Pool 当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到mu ...

  4. Python多进程库multiprocessing中进程池Pool类的使用

    问题起因 最近要将一个文本分割成好几个topic,每个topic设计一个regressor,各regressor是相互独立的,最后汇总所有topic的regressor得到总得预测结果.没错!类似ba ...

  5. python 全栈开发,Day40(进程间通信(队列和管道),进程间的数据共享Manager,进程池Pool)

    昨日内容回顾 进程 multiprocess Process —— 进程 在python中创建一个进程的模块 start daemon 守护进程 join 等待子进程执行结束 锁 Lock acqui ...

  6. python 进程池pool简单使用

    平常会经常用到多进程,可以用进程池pool来进行自动控制进程,下面介绍一下pool的简单使用. 需要主动是,在Windows上要想使用进程模块,就必须把有关进程的代码写if __name__ == ‘ ...

  7. Python多进程库multiprocessing中进程池Pool类的使用[转]

    from:http://blog.csdn.net/jinping_shi/article/details/52433867 Python多进程库multiprocessing中进程池Pool类的使用 ...

  8. python 进程池pool

    进程池子 当你成千上万的业务需要创建成千上万的进程时,我们可以提前定义一个进程池 from multiprocessing import Pool p = Pool(10) #进程池创建方式,类似空任 ...

  9. 进程池----Pool(老的方式)----回调

    之后的进程池使用的是 ProcessPoolExecutor,它的底层使用的就是pool 为什么要有进程池?进程池的概念. 在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星 ...

随机推荐

  1. windows如何安装python zmq

    百度windows python zmq 安装,真的是佩服百度还能活到今天,搜到的结果是各种yum 安装,各种jmq怎么安装,更有甚者直接整源代码编译,忍无可忍,所以自己写下这一篇自己探索出来的安装方 ...

  2. [置顶] kubernetes资源对象--ResourceQuotas

    概念 Resource Quotas(资源配额,简称quota)是对namespace进行资源配额,限制资源使用的一种策略. K8S是一个多用户架构,当多用户或者团队共享一个K8S系统时,SA使用qu ...

  3. JavaScript的filter用法

    Js的有些操作会改变原来的对象:有些操作则不会改变原来对象. 数组的filter方法就不会改变原来数组 利用filter,可以巧妙地去除Array的重复元素: 'use strict'; var r, ...

  4. 可以使用foreach遍历循环的条件

    大话C#中能使用foreach的集合的实现 转自:http://www.cnblogs.com/tangzhengyue/p/3339936.html   大家都知道foreach的语法: forea ...

  5. 2017.3.31 spring mvc教程(六)转发、重定向、ajax请求

    学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变 ...

  6. 转: Linux 上的常用文件传输方式介绍与比较

    from:  https://www.ibm.com/developerworks/cn/linux/l-cn-filetransfer/ ftp ftp 命令使用文件传输协议(File Transf ...

  7. web前端性能优化汇总

    一.概述 web前端性能优化主要点为:减少HTTP请求,减小请求文件大小.其他优化. 二.优化细节 1.减少HTTP请求 (1)使用缓存 (2)雪碧图 (3)合并文件 (4)将javascript和c ...

  8. TabControl

    1. ItemsSource="{Binding GroupList}" SelectedItem="{Binding SelectedGroupItem,Mode=Tw ...

  9. 一分钟搞定触手app主页酷炫滑动切换效果

    代码地址如下:http://www.demodashi.com/demo/12826.html 前言: 前几天在看手机直播的时候,自己就用上了触手app.一进到主页就看上了里面页面切换的效果,自己想这 ...

  10. 使用Maven整合SSH总结

    本人自己进行的SSH整合,中间遇到不少问题,特此做些总结,仅供参考. 项目环境: struts-2.3.31 + spring-4.3.7 + hibernate-4.2.21 + maven-3.3 ...