1. error/1

主要是系统用来定义内部错误的: Erlang内建的run time error 一共有10种:

function_clause/case_clause/if_clause/badmatch/badarg/undef/badarith/badfun/badarity/system_limit, 比如:

 1> erlang:binary_to_list(1).
** exception error: bad argument
in function binary_to_list/1
called as binary_to_list(1)

这上面就是触发了error/1,我们也可以手动触发一下。

 2> erlang:error(badarg).
** exception error: bad argument        

注意到erlang直接把badarg这种内建的error转成更详细的bad argument,

更进一步,我们也可以使用error/1定义自己的错误

3> erlang:error("this is my own error").
** exception error: "this is my own error"

这一次,自定义的错就没有被erlang shell认出来。

2. exit/1 exit/2

exit有internal exits 和 external exits的区别,我们可以使用exit(Pid,Reason)让别一个进程退出。

exit/1和error/1非常相似,很多时候可以通用,便是exit语境是退出,更适合于进程退出的情况,还有一个区别就是

exit/1不会带调用的stack trace信息(方便让其它进程退出时不用带非常大的调用信息,更轻量)。但是error/1会带。

4> catch exit(test).
{'EXIT',test}
5> catch error(test).
{'EXIT',{test,[{erl_eval,do_apply,6,
[{file,"erl_eval.erl"},{line,674}]},
{erl_eval,expr,5,[{file,"erl_eval.erl"},{line,431}]},
{shell,exprs,7,[{file,"shell.erl"},{line,686}]},
{shell,eval_exprs,7,[{file,"shell.erl"},{line,641}]},
{shell,eval_loop,3,[{file,"shell.erl"},{line,626}]}]}} 

3. throw/1

throw/1 它最常用配合 try...of catch 处理嵌套case(可以快速跳出),它所携带的信息最少(比exit/1还少一个'EXIT'):

6> catch throw(2+2).
4
7> catch 2+2
4     

上面2个case用的catch,都区分不出结果是throw出来的,还是正常计算得到的结果,所以这也是推荐使用try .. of catch的原因:

8> try throw(2+2) of
8> V -> {ok, V}
8> catch
8> throw:V -> {error, V}
8> end.
{error,4} 

4. 总结

进程退出使用exit/1或exit/2, 想快速跳出recursion或快速跳回Top-Level函数时用throw/1,尽量不要使用error/1,

如果需要得到调用的stack trace信息,可以自己显式的调用erlang:get_stacktrace().得到当前进程最新一次Exception时的的stacktrace。

5. 扩展(gen_server中的几种退出进程方法比较)

 我们在gen_server中安全有5种退出方法,
5.1. 在init不成功时返回{stop, Reason} 退出;
5.2. 处理消息出错,或正常退出时返回{stop, Reason, NewState});
5.3. 使用exit直接退出进程;
5.4. 使用throw退出进程;
5.5. 使用error退出进程(由于我们前面讲了error主要用于定义内部错误,所以不推荐使用)。

前两种是显而易见的,关键是后三种方式退出与前者的区别。
先来理一理{stop, Reason, NewState},直接exit, 直接throw三者的区别。
try_dispatch(Mod, Func, Msg, State) ->
try
{ok, Mod:Func(Msg, State)}
catch
throw:R ->
{ok, R};
error:R ->
Stacktrace = erlang:get_stacktrace(),
{'EXIT', {R, Stacktrace}, {R, Stacktrace}};
exit:R ->
Stacktrace = erlang:get_stacktrace(),
{'EXIT', R, {R, Stacktrace}}
end.

使用stop就是正常退出,不带stack trace信息(他本来就没有crash,也没有stack信息)

使用exit退出,它带了stack trace信息。

使用throw退出,它没有带stack trace信息,且要throw出来的term要是符合gen_server标准,比如
{noreply, NewState}
{reply, ok, NewState}
{stop, normal, NewState}

  

明白了以上区别,就很容易选择了:
1.exit也是用于不可预期的错误,需要返回它的stack trace信息用来记录,所以不推荐在gen_server中主动调用exit;
2.throw可以快速回应本次消息的处理,简化代码的嵌套case逻辑,不过要注意,throw出来的一定是一个符合gen_server标准的东西,不然会报错。
3.正常可预期的逻辑都都使用{stop,Reason, NewState}处理。 

我们再深入一点:
当我们stop时的Reason不是 normal | shutdown | {shutdown,term()} 时会在kernel log中打印日志
 

Notice that for any other reason than normal, shutdown, or {shutdown,Term}, the gen_server process is assumed to terminate because of an error and an error report is issued using error_logger:format/2.

比如这样:
=ERROR REPORT==== 31-Oct-2016::15:10:44 ===
** Generic server test_throw_exit terminating
** Last message in was go
** When Server state == {state}
** Reason for termination ==
** not_shutdown_term

所以,如果我们在正常退出或shutdown时不需要那一列烦人的log,就把reason定义为三者中的一种就行了。

具体源码可见: https://github.com/erlang/otp/blob/maint/lib/stdlib/src/gen_server.erl#L809

总结:
1. 在gen_server中正常退出,请回复{stop, Reason, NewState},
2. 如果是要快速结束此次消息的退出可以使用throw(term()),其中term()符合gen_server规范(和正常返回的值一样),
3. 正常逻辑里面不推荐使用exit/error来处理,分携带多余的stack trace信息。 
 

6. 参考资料:

  Erlang官方文档:http://erlang.org/doc/reference_manual/errors.html

Learnyousomeerlang关于Exceptions的介绍: http://learnyousomeerlang.com/errors-and-exceptions

[Erlang37]error/1 exit/1 exit/2 throw/1的区别的更多相关文章

  1. error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status

    Windows服务器Azure云编译安装MariaDB教程 www.111cn.net 编辑:future 来源:转载 安装MariaDB数据库最多用于linux系统中了,下文给各位介绍在Window ...

  2. svn Error: post-commit hook failed (exit code 127) with output

    Command: Commit Modified: C:\Users\xsdff\Desktop\project\index.html Sending content: C:\Users\xsdff\ ...

  3. error: ld returned 1 exit status 和 error:undefined reference

    undefined reference 往往是链接时出现错误,无法解析引用.这篇文章总结的很好undefined reference问题总结 error: ld returned 1 exit sta ...

  4. docker pull报错failed to register layer: Error processing tar file(exit status 1): open permission denied

    近来在一个云主机上操作docker pull,报错如下: failed to register layer: Error processing ): open /etc/init.d/hwclock. ...

  5. Arduino上“Collect2.exe: error: ld returned 5 exit status”错误的解决方法

    1.运行环境 Windows xp; Arduino1.6.11 IDE. 2.问题 在Arduino编译时,经常出现如下的错误: collect2.exe: error: ld returned 5 ...

  6. docker mac 命令行登录报错处理 : Error saving credentials: error storing credentials - err: exit status 1

    参考:https://blog.csdn.net/xufwind/article/details/88756557 比较新版本的docker命令行登录会出现以下错误: Error saving cre ...

  7. moc_XXXX.o:(.data.rel.ro._ZTI12CalculatorUI[_ZTI12CalculatorUI]+0x10): undefined reference to `typeinfo for QWidget' collect2: error: ld returned 1 exit status make: *** [Makefile:144: myCalculator]

    main.cpp:(.text.startup+0x22): undefined reference to `QApplication::QApplication(int&, char**, ...

  8. DevC++ 报错[Error] Id returned 1 exit status

    DevC++ 报错[Error] Id returned 1 exit status 起因 学校机房的计算机总是二次编译总是报错 报错提示 [Error] Id returned 1 exit sta ...

  9. Dev C++编写C/C++程序 出现[Error] ld returned 1 exit status报错分析及解决

    debug系列第一弹,不知道大家写程序的时候是不是都遇到过如题的报错. 我本人是经常遇到这行熟悉的令人不知所措的报错,可能是我太笨了 有时候百度无果也差不到原因,那就汇总一下目前我遇到的情况吧--持续 ...

随机推荐

  1. 【原】自定义UIPageControl的圆点

    在下面的两种情况下会导致圆点贴图刷新: 1.用户调用setCurrentPage:(NSInteger)currentPage时 所以重载这个函数便可拦截 2.点击圆点矩形区域时     这说明,我们 ...

  2. python super

    http://hi.baidu.com/thinkinginlamp/item/3095e2f52c642516ce9f32d5 Python中对象方法的定义很怪异,第一个参数一般都命名为self(相 ...

  3. 用luke看索引

    Luke是一个用于Lucene搜索引擎的第三方工具,它可以访问现有Lucene的索引,并允许您显示和修改.可以看每篇文档建立了哪些索引,验证有没有成功建立了索引.不然建立了,不能确定有没有成功. 可以 ...

  4. LightSpeed 的Left Join Bug解决方案

    在使用LightSpeed对数据库进行Left Join或Right Join操作时,经常会报一些匪夷所思的异常. 明明表没有问题,表面上语句写的也没问题,可总是报错.看分析器里的SQL就知道了,是L ...

  5. CentOS下安装MySQL

    首先通过网络链接的方式在线安装上mysql服务器端吧!(备注:我开始登录服务器的时候是用的其他用户而不是超级管理员,所以安装MySQL的时候需要切换到超级管理员才可以实现软件的正确安装.命令则是:su ...

  6. 烂泥:KVM虚拟机的关机与开启

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 我们在开启与关闭KVM虚拟机时,一般是通过start.shutdown.reboot等命令来进行.但是有时候我们会发现在使用shutdown.reboo ...

  7. SQLAlchemy 中文文档翻译计划

    SQLAlchemy 中文文档翻译计划已启动. Python 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质.交流群:467338606. 希望大家能够勇敢地去翻译和改进翻译.虽然我 ...

  8. Linux objcopy命令

    一.简介 [功能] 将目标文件的一部分或者全部内容拷贝到另外一个目标文件中,或者实现目标文件的格式转换. [描述] objcopy工具使用BFD库读写目标文件,它可以将一个目标文件的内容拷贝到另外一个 ...

  9. 【node.js】安装express后,'express' 不是内部或外部命令的问题

    因express默认安装是最新的版本,已经是4.x.x的版本.而最新express4.0+版本中将命令工具分出来了,所以必须要安装express-generator,执行: D:\TOOLS\Node ...

  10. POJ 2513 Colored Sticks(欧拉回路,字典树,并查集)

    题意:给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的.   无向图存在欧拉路的充要条件为: ①     图是连通的: ②     所有节 ...