erlang supervisor中启动普通的进程
文字部分转自: http://1234n.com/?post/qou3eb
supervisor的子进程
一开始使用supervisor的时候,我用的是init/1返回子进程规格列表的方式,并且所有子进程只有两种类型,一种是supervisor进程,一种是gen_server。
但这次代码重构中,我遇到一个情况。如果我可以启动普通的进程而不是gen_server,我就可以把一些我觉得没必要做成gen_server的模块代码精简掉。因为一些模块代码完全没用到任何gen_server的优势,只是借gen_server来做为supervisor的子进程启动。于是我便开始实验如何在supervisor中启动普通的进程。
通过实验,我发现我原先对supervisor的理解完全是没有根据的猜测,果然实践才是检验真理的唯一标准。
首先,我原以为supervisor的子进程规格中提供的Module、Function、Arguments就是子进程的入口,supervisor会通过它来自己启动子进程。但实际上,子进程规格提供的是子进程的启动函数入口,supervisor通过调用这个入口函数来启动子进程,而这个函数通过返回{ok, Pid}来告诉supervisor子进程创建成功。
其次,并不是简单的通过spawn在子进程启动函数中启动一个进程然后返回{ok, Pid}就可以让子进程拥有出错自动重启的功能。实际上,需要使用proc_lib:spawn_link或者proc_lib:start_link启动子进程,才能在子进程出错退出时让supervisor自动重启它。
上面的第二点,我是通过阅读gen_server的代码才了解到的,因为一开始我用来做实验的代码没有用spawn(因为第一点的错误理解),但这个问题很容易就发现了,接着我用了spawn看似正确启动了子进程,但实际上这些子进程一旦出错退出就不会再被启动。我换gen_server实验了一遍,确信用gen_server是可以重启的。于是我便阅读gen_server:start_link的代码一探究竟,从源码中可以看到gen_server模块调用gen模块来启动进程,而gen模块最终通过proc_lib:start_link来启动进程。
proc_lib:start_link和proc_lib:spawn_link的不同之处在于,前者是同步创建子进程,后者是异步创建子进程,proc_lib:start_link调用后会阻塞,直到子进程初始化完毕,调用proc_lib:init_ack后才返回。而proc_lib:spawn_link一调用就会立即返回子进程ID。
测试代码(其中有和主题无关的测试代码,请大家无视):
parent_sup.erl
-module(parent_sup).
-behaviour(supervisor). -export([start_link/0]).
-export([init/1]). start_link() ->
supervisor:start_link(?MODULE, []). init(Args) ->
{ok, {{one_for_one, 1, 60},
[%%{child, {child, start_link, ["hello"]},
%% permanent, brutal_kill, worker, [child]},
{parent, {parent, start_link, ["args"]},
permanent, brutal_kill, worker, [parent]}
]}}.
parent.erl
-module(parent).
-export([start_link/1]).
-export([start_loop/1]). start_link(Args) ->
io:format("~p~n", [Args]),
Ret = proc_lib:start_link(?MODULE, start_loop, [self()]),
io:format("~p~n", [Ret]),
Ret. start_loop(Parent) ->
proc_lib:init_ack(Parent, {ok, self()}),
loop(). loop() ->
receive
Args ->
io:format("~p~n", [Args])
end.
测试命令:
erl -boot start_sasl
22> c(parent).
{ok,parent}
23> c(parent_sup).
parent_sup.erl:10: Warning: variable 'Args' is unused
{ok,parent_sup}
24> c(parent).
{ok,parent}
25> parent_sup:start_link().
"args"
{ok,<0.123.0>} =PROGRESS REPORT==== 16-Jul-2013::11:05:24 ===
supervisor: {<0.122.0>,parent_sup}
started: [{pid,<0.123.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}]
{ok,<0.122.0>}
26> exit(pid(0,123,0), some_reason). =SUPERVISOR REPORT==== 16-Jul-2013::11:06:28 ===
Supervisor: {<0.122.0>,parent_sup}
Context: child_terminated
Reason: some_reason
Offender: [{pid,<0.123.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}] =SUPERVISOR REPORT==== 16-Jul-2013::11:06:28 ===
Supervisor: {<0.122.0>,parent_sup}
Context: shutdown
Reason: reached_max_restart_intensity
Offender: [{pid,<0.123.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}] ** exception exit: shutdown
27> c(parent).
{ok,parent}
28> c(parent_sup).
parent_sup.erl:10: Warning: variable 'Args' is unused
{ok,parent_sup}
29> parent_sup:start_link().
"args"
{ok,<0.138.0>} =PROGRESS REPORT==== 16-Jul-2013::11:07:19 ===
supervisor: {<0.137.0>,parent_sup}
started: [{pid,<0.138.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}]
{ok,<0.137.0>}
30> exit(pid(0,138,0), some_reason).
"args" =SUPERVISOR REPORT==== 16-Jul-2013::11:07:28 ===
Supervisor: {<0.137.0>,parent_sup}
Context: child_terminated
Reason: some_reason
Offender: [{pid,<0.138.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}] {ok,<0.140.0>} =PROGRESS REPORT==== 16-Jul-2013::11:07:28 ===
supervisor: {<0.137.0>,parent_sup}
started: [{pid,<0.140.0>},
{name,parent},
{mfargs,{parent,start_link,["args"]}},
{restart_type,permanent},
{shutdown,brutal_kill},
{child_type,worker}]
true
31>
erlang supervisor中启动普通的进程的更多相关文章
- 在Hudson Job中启动daemon进程
场景 在Hudson中新建一个Job用于构建Web工程,在Job的构建脚本的最后会启动Jetty,观察发现Jetty启动之后一小段时间,进程就终止了. 环境 CentOS 6,Hudson 3.0 ...
- jenkin构建项目执行脚本后,脚本中启动的进程也随之关闭的解决办法
问题描述: 之前用jenkins构建项目(maven项目)后都是通过ssh先将war文件推送到远程服务器,然后执行远程的脚本(更新项目,重启tomcat),一直没有出现问题,今天使用jenkins构建 ...
- Erlang虚拟机的启动
Erlang虚拟机的启动 erl实际上是一个shell脚本,设置几个环境变量之后,调用执行erlexec.erlexec的入口点在 otp_src_R15B01/erts/etc/common/erl ...
- [Erlang13]怎么把一个普通的进程挂入Supervisor监控树?
简单来说:应该是在调用的start_link返回一个{ok,Pid}就可以把这个进程放入监控树Supervisor里面: -module(worker). -author("zhongwen ...
- Android系统在新进程中启动自定义服务过程(startService)的原理分析
在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验.Android系统为我们提供了一个Service类,我们可以实现 ...
- Docker学习笔记 - 在运行中的容器内启动新进程
docker psdoker top dc1 # 容器情况# 在运行中的容器内启动新进程docker exec [-d] [-i] [-t] 容器名 [command] [args]docker ex ...
- 在linux中安装jdk以及tomcat并shell脚本关闭启动的进程
在命令行模式中输入uname -a ,如下图,当界面展示i386就说明本linux系统为32版本,就在官网下载对应jdk版本,或者直接到我的网盘上下载http://pan.baidu.com/s/1c ...
- C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?
原文:C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思? 在 .NET 中创建进程时,可以传入 ProcessStartInfo ...
- supervisor之启动rabbitmq报错原因
前言 今天重启了服务器,发现supervisor管理的rabbitmq的进程居然启动失败了,查看日志发现老是报错,记录一下解决的办法. 报错:erlexec:HOME must be set 找了网上 ...
随机推荐
- 18 个最佳代码编辑器/IDE推荐
本文为开发人员收录了18个最好的代码编辑器/IDE工具,希望你会喜欢. 1) chocolatapp Chocolat是最新出现的一款强大的Mac系统文本编辑器,兼具原生的Cocoa及强大的文本编辑功 ...
- IntelliJ IDEA的几种常见的快捷键
在编写代码的时候直接输入psv就会看到一个psvm的提示,此时点击tab键一个main方法就写好了. psvm 也就是public static void main的首字母. 依次还有在方法体内键入f ...
- Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理)
Spark Shuffle 堆外内存溢出问题与解决(Shuffle通信原理) http://xiguada.org/spark-shuffle-direct-buffer-oom/ 问题描述 Spar ...
- [React + Functional Programming ADT] Create Redux Middleware to Dispatch Multiple Actions
We only have a few dispatching functions that need to be known by our React Application. Each one ac ...
- 使用Sublime经验分享
Sublime轻量级.可是绝对是神一样的编辑器. 1.代码清晰美观 2.能够选择文件夹作为文件结构文件夹显示在左側 3.以tab的形式打开多个页面在同一个窗体内 设置方法例如以下: Preferenc ...
- .Net Framework 之 托管代码和非托管代码的区别
一.什么是托管代码(managed code)? 托管代码:是微软的中间语言(IL),即微软中间语言MSIL(Microsoft Interspace Language). “ 源代码→机器码 ”运行 ...
- win7之64位下安装oracle11g遇到问题和不能删除干净的问题
今天在win7下装了oracle11g 删了又卸 来来回回重启了4.5次,结合网上是解释归纳下几点: 一.win64_11gR2_database_1of2.zip和win64_11gR2_datab ...
- 操作系统开发之——一个简单的Bootsect
先吓唬一下读者朋友呵呵,直接发代码:(这是UOS操作系统的Bootsect)(有兴趣的朋友能够增加我们,联系方式在最后) ;------------------------------ ;文件名称:B ...
- 算法笔记_158:算法提高 逆序排列(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 编写一个程序,读入一组整数(不超过20个),并把它们保存在一个整型数组中.当用户输入0时,表示输入结束.然后程序将把这个数组中的值按逆序重新存 ...
- hibernate list和iterate
list方法会一次查出所有内容,放在list里和缓存中.再次查询同一内容仍然会去数据库重新查一遍,并刷新缓存. iterate方法会一次查出所有内容的ID,等用到某个ID对应的内容时又会去根据主键查询 ...