关于erlang的进程池
有两种情况需要考虑使用进程池管理erlang进程。
一种是普通erlang进程,很便宜,一次可以并行很多(默认32K,当然可以调整vm参数设置更大),但是这不意味着可以无限制的使用,实际上轻松的达到上限是很容易的(想想发明国际象棋的那位向国王请赏的办法,类似的,一个进程开两个,两个再开四个,四个再开8个。。。。,很容易就达到了上限),因此有时候我们需要对进程进行管理,避免无限制的使用累垮系统。
另一种是比较特殊的erlang进程,它有特殊的使用,在运行时可能比较耗资源(也比较耗时),就像数据库连接池。
以上都可以用进程池的方式管理同类进程:池的大小是有限的,超出后的进程就只能在池外排队等候了。
可惜官方还没有提供现成的进程池模块。有一些开源的erlang进程池可供选择,比如:poolboy,hottub, poolygen_server_pool,
0. 一个进程池的实现例子
在Learn Your Some Erlang中有一个进程池的设计与实现的例子,从中可以了解进程池的设计思路。
简单的说,每个进程池顶端是一个supervisor,它下面有一个gen_server和一个supervisor。后者是simple_one_for_one策略的supervisor,前者管理这个supervisor,例如,前者通知后者创建一个工作进程(通过supervisor:start_child启动工作进程)。
1. 重型进程用poolboy
如果有多个进程需要运行,这些进程运行的都是相同的代码(例如某个gen_server模块,或者其它模块只要带有start_link函数),这些进程的特点是比较耗资源,是计算或者IO密集的。例如提供数据库查询的服务进程,建立数据库连接就比较耗时,(当然以后的查询数据库等待结果也可能很费时)。对这类进程,如果临时要用到时新开一个进程,会在数据库连接上先耗去好多时间,这时服务使用者只能干等着。一个很自然的想法就是,不管会不会用到先建立一批连接好数据库的服务进程再说,这些预先启动的服务进程就构成了一个服务进程池,来一个请求就取出一个闲置的服务进程直接使用,用完放回进程池就行了。
poolboy就是干这个的,这是一个开源的erlang进程池,代码量很小,三个程序文件总共不到400行代码。这个模块的结构如图所示。这里比较奇怪的地方是supervisor是直接挂在gen_fsm下的。这打破了我的一个思维定思,以前一直认为supervisor也应该挂在supervisor下。
poolboy比较适合为重量级的进程建池。重量级是指进程的创建和使用比较耗资源,一般这类进程的总量也有限度。如果是那种轻量级的进程,例如生存时间很短、用完就扔、数量多少也不定的进程,似乎并不适合poolboy。这类进程可参考Build applications with OTP的进程池例子。
使用:
从进程池中取出服务进程,使用,用完后归还给进程池:
Worker = poolboy:checkout(PoolName), Reply = gen_server:call(Worker, WorkerFun),poolboy:checkin(PoolName, Worker),Reply.