首页 > 代码库 > a simple erlang process pool analysis
a simple erlang process pool analysis
a simple erlang process pool analysis
这是一个简单的erlang进程池分析,是learn you some erlang for Great Good
里面的一个example,详细的内容可到官网查看!
主要的流程图
实现原理
这个的例子的实现原理官网都有比较详细的说明,主要模块在ppool_serv
中,ppool_serv
是一个gen_server behaviour
, 而ppool_sup
是一个one_for_all
的策略,如果ppool_serv
或者worker_sup
出现问题,彼此也没有存在的必要了。
这里ppool_serv 和 worker_sup的实现,使用了一个简单的技巧,因为worker_sup不是ppool_sup直接调用生成的,它是由ppool_serv控制生成的:
%% Gen server init({Limit, MFA, Sup}) -> %% We need to find the Pid of the worker supervisor from here, %% but alas, this would be calling the supervisor while it waits for us! self() ! {start_worker_supervisor, Sup, MFA}, {ok, #state{limit=Limit, refs=gb_sets:empty()}}.
woker_sup
由ppool_serv
自己在init
函数中,发给自己一个Message,然后在回调函数中才生成:
handle_info({start_worker_supervisor, Sup, MFA}, S = #state{}) -> {ok, Pid} = supervisor:start_child(Sup, ?SPEC(MFA)), link(Pid), {noreply, S#state{sup=Pid}};
如果他们一起直接生产,那么会产生死锁,
当然,他这里的生成顺序,可以自己修改一下,也不会出现死锁。
gen_serv的主要数据结构
-define(SPEC(MFA), {worker_sup, {ppool_worker_sup, start_link, [MFA]}, temporary, 10000, supervisor, [ppool_worker_sup]}). -record(state, {limit=0, sup, refs, queue=queue:new()}).
?SPEC(MFA)
, 这里的MFA
指明一类Task
,所以同一个ppool_worker_sup
,不会有不同类型的Task,它的策略也是simple_one_for_one
.
在这个例子中,使用了一个gen_server -- nnager module 作为Task,这个Task的参数为:{Task, Delay, Max, SendTo}, Task标示任务名字,Delay作为超时时间,只是标示这个任务是有超时限制的,也是一个调试技巧,Max为最大超时次数,SendTo用来发送信息给回调进程,这个进程可以是shell, 如果是shell,flush()就会收到信息。
record
用来标识一些主要的信息,Limit为进程池的大小限制,sup开始为ppool_sup的pid(),在生成woker_sup进程后,就变成worker_sup的进程pid(),因为ppool_serv的主要交流对象还是worker_sup和worker(Task); refs(gb_set)为woker的进程链接,这样可以在worker进程down掉或者done时,从线程池中剔除掉;queue为任务队列,当任务大于limit时,就把多余的任务放到queque中,等到进程池有空闲时,就从中pop出任务,接着处理。
这里有些局限的地方:1.每次的任务都是新建的进程去处理,就是说进程的生命周期跟任务的生命周期是一样的,可以把进程跟任务分离出来,让进程不随任务的结束而结束(当然这的任务就不要是gen_server,gen_fsm这些,因为这些也是spawn出来的进程),这样进程开销理论上一次初始化就行了,虽然进程在erlang中开销比较少;2.队列没有大小限制