Erlang:在这种情况下,使用try-catch或case语句哪个更有效?
假设我在Erlang中有一个函数fn1(),如果函数执行成功,它返回Erlang:在这种情况下,使用try-catch或case语句哪个更有效?,erlang,performance,Erlang,Performance,假设我在Erlang中有一个函数fn1(),如果函数执行成功,它返回{ok,Result},如果有错误,它返回{error,“ErrorReason”} 现在,在另一个函数fn2()中,我调用fn1(),我需要检查fn1的结果,并且仅当它是{ok,result}时才继续 我想,我可以使用任何一种情况或尝试捕获。但是效率是我最关心的问题,我想知道下面两种方法中哪一种更有效: 尝试捕获方法 fn2() -> try {ok, Result} = fn1(), %D
{ok,Result}
,如果有错误,它返回{error,“ErrorReason”}
现在,在另一个函数fn2()中,我调用fn1(),我需要检查fn1的结果,并且仅当它是{ok,result}
时才继续
我想,我可以使用任何一种情况或尝试捕获。但是效率是我最关心的问题,我想知道下面两种方法中哪一种更有效:
尝试捕获
方法
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
fn2() ->
Res = fn1(),
case Res of
{ok, Result} ->
%Do something with Result
ok;
{error, Reason} ->
Reason
end.
案例
方法
fn2() ->
try
{ok, Result} = fn1(),
%Do something with Result
ok
catch
throw:Term -> Term;
exit:Reason -> {exit, Reason};
error:Reason -> {error,{Reason,erlang:get_stacktrace()}}
end.
fn2() ->
Res = fn1(),
case Res of
{ok, Result} ->
%Do something with Result
ok;
{error, Reason} ->
Reason
end.
case方法将更有效,因为它只是模式匹配,不涉及构建调用堆栈和其他内容 在这两个示例中,您都将在本地处理“错误”,因此在try-catch中没有任何意义。有时您可能会看到如下情况:
fn2() ->
{ok, Result} = fn1(),
%Do stuff with Result
ok.
这里的意图是,如果fn1()没有返回ok,则让fn2()抛出一个坏匹配。你让其他“上级”处理问题。例如,这可能会终止您的流程,并使您的主管创建一个新流程。您应该始终进行测量,以找出类似的问题 您的代码也不做您认为它做的事情 -module(glurk). -compile(export_all). fn2() -> try {ok, Result} = fn1(), %Do something with Result ok catch throw:Term -> Term; exit:Reason -> {exit, Reason}; error:Reason -> {error,{Reason,erlang:get_stacktrace()}} end. fn1() -> {error, a}. 实际上,您的第一个代码有一个更微妙的错误 fn2() -> try {ok, Result} = fn1(), %Do something with Result ok catch throw:Term -> Term; exit:Reason -> {exit, Reason}; error:Reason -> {error,{Reason,erlang:get_stacktrace()}} end. fn2()-> 尝试 {ok,Result}=fn1(), %做一些有结果的事情 好啊 抓住 抛出:术语->术语; 退出:原因->{exit,Reason}; 错误:Reason->{error,{Reason,erlang:get_stacktrace()} 结束。 想想这个。捕获的错误案例本身并不处理错误 它们只返回元组,如{exit,Reason}或{error,Reason}。这意味着 下一层(即fn2的调用方)也将不得不进行检查 返回错误-如果在所有级别重复此操作,代码将变得一团糟 “erlang”方法是在程序的顶部有一个try-catch,然后终止 如果发生错误,则突然退出(为什么) 事实上,您甚至不应该这样做-您应该将您的流程链接到另一个流程 然后,有问题的进程将死亡,“其他进程将修复错误” 异常会向上传播到调用堆栈并传递到链接的进程 治疗。因此,我们有两种类型的进程——没有内置错误处理的进程
以及只进行错误处理的进程。您确实希望尝试避免像瘟疫一样的尝试/捕获。这在Erlang中是一个非常罕见的习惯用法-实际上只在几个特殊情况下使用:
- 您正在检查用户提供的 你不能保证 它将是“正确的”
- 在那里你有一些
深度嵌套和
在错误条件下展开它
太贵了
- 像门西亚交易
- 或者在解析器/词法分析器中
Test/catch在C++等语言中是必不可少的,在应用程序中存在或错误时不稳定,但在这种情况下Erlang稳定,进程崩溃但不会使系统下降。 您应该对快乐路径进行编程,匹配返回值,如果应用程序偏离预期,则让它崩溃。崩溃告诉您有问题,并告诉您修复它
try/catch的问题在于,它可以简单地掩盖问题,甚至更糟糕的是,将最终崩溃从应该发生的地方(在您包装的表达式中)移开,并使它出现在其他地方-您的编程逻辑期望它成功的地方=这使得调试更加困难为快乐之路编程并让它崩溃在你第一次这么做时是非常令人不安的,这感觉就像是不穿衣服出门,但实际上你很快就习惯了:)在这种情况下,不管什么更有效,您肯定应该使用
案例
选项,因为它更简洁地描述了正在发生的事情。您的fn1()
在此返回一个值,指示是否存在成功值或错误。在案例
版本中,您直接与此匹配,而在尝试
版本中,您与成功值匹配,如果返回错误,成功值将生成错误。它是不必要的复杂,隐藏了正在发生的事情,因此它是一种糟糕的编程风格,应该避免
正如Gordon已经指出的那样,进行try
会捕捉到比您可能想要的更多的错误,从而掩盖您应该看到的其他真实错误
案例
在这里也会更快,但差异可能很小。清晰、简洁和良好的编程风格更为重要 案例总是更有效,但差异很小,更重要的是,在您的特定案例中,什么更有意义。特别是,哪种方法产生的代码更容易理解。请参见此基准:
%% Results:
%% 7> errors:run_normal(100).
%% {9,ok}
%% 8> errors:run_normal(1000).
%% {107,ok}
%% 9> errors:run_normal(10000).
%% {856,ok}
%% 10> errors:run_normal(1000, 10).
%% {263,ok}
%% 11> errors:run_wcatch(10000).
%% {2379,ok}
%% 12> errors:run_wcatch(1000, 10).
%% {401,ok}
%% 18> errors:run_normal_cplx(10000, 50).
%% {7910,ok}
%% 19> errors:run_wcatch_cplx(10000, 50).
%% {10222,ok}
-模块(错误)。
-编译(全部导出)。
正常运行(迭代)->
获取结果(迭代,fun()->normal()结束)。
正常运行(迭代,级别)->
获取结果(迭代,fun()->deepnormal(Level)end)。
运行(迭代)->
获取结果(迭代,fun()->wcatch()结束)。
运行(迭代,级别)->
获取_结果(迭代,fun()->deepwcatch(级别)结束)。
运行\u正常\u cplx(迭代)->
获取结果(迭代,fun()->normal\u complex()结束)。
运行\u正常\u cplx(迭代,级别)->
获取结果(迭代,fun()->deepnormal_复杂(级别)结束)。
运行\u wcatch\u cplx(迭代)->
获取结果(迭代,fun()->wcatch_complex()结束)。
运行\u wcatch\u cplx(迭代,级别)->
获取结果(迭代,fun()->deepwcatch_复杂(级别)结束)。
%%------------------------------------------------------------------------------
获取结果(迭代、乐趣)->
计时器:tc(fun()->运行(迭代,fun)结束)。
跑步(0,乐趣)->
%% Results:
%% 7> errors:run_normal(100).
%% {9,ok}
%% 8> errors:run_normal(1000).
%% {107,ok}
%% 9> errors:run_normal(10000).
%% {856,ok}
%% 10> errors:run_normal(1000, 10).
%% {263,ok}
%% 11> errors:run_wcatch(10000).
%% {2379,ok}
%% 12> errors:run_wcatch(1000, 10).
%% {401,ok}
%% 18> errors:run_normal_cplx(10000, 50).
%% {7910,ok}
%% 19> errors:run_wcatch_cplx(10000, 50).
%% {10222,ok}