轻作



重拾写作的乐趣

Erlang异常性能

2020.03.04

因为erlang没有提前返回, 所以需要提前返回, 异常是一个不错的想法, 但又怕有性能问题, 下面来测试下。

ts_exception() ->

    {LoopOnly, _} = timer:tc(?MODULE, loop_only, [1000000, none, undefined, undefined]),

    {LoopInTryCatchOnly, _} = timer:tc(?MODULE, loop_in_try_catch_only, [1000000, none, undefined]),
    {LoopInTryCatchStacktraceOnly, _} = timer:tc(?MODULE, loop_in_try_catch_stacktrace_only, [1000000, none, undefined, undefined]),
    {LoopInCatchOnly, _} = timer:tc(?MODULE, loop_in_catch_only, [1000000, none]),

    {TryCatchThrow, _} = timer:tc(?MODULE, loop_try_catch, [1000000, throw, undefined]),
    {TryCatchError, _} = timer:tc(?MODULE, loop_try_catch, [1000000, error, undefined]),
    {TryCatchExit, _} = timer:tc(?MODULE, loop_try_catch, [1000000, exit, undefined]),

    {TryCatchStacktraceThrow, _} = timer:tc(?MODULE, loop_try_catch_stacktrace, [1000000, throw, undefined, undefined]),
    {TryCatchStacktraceError, _} = timer:tc(?MODULE, loop_try_catch_stacktrace, [1000000, error, undefined, undefined]),
    {TryCatchStacktraceExit, _} = timer:tc(?MODULE, loop_try_catch_stacktrace, [1000000, exit, undefined, undefined]),

    {CatchStacktraceThrow, _} = timer:tc(?MODULE, loop_catch, [1000000, throw]),
    {CatchStacktraceError, _} = timer:tc(?MODULE, loop_catch, [1000000, error]),
    {CatchStacktraceExit, _} = timer:tc(?MODULE, loop_catch, [1000000, exit]),


    io:format("LoopOnly:~tp~n", [LoopOnly]),
    io:format("LoopInTryCatchOnly:~tp~n", [LoopInTryCatchOnly]),
    io:format("LoopInTryCatchStacktraceOnly:~tp~n", [LoopInTryCatchStacktraceOnly]),
    io:format("LoopInCatchStacktraceOnly:~tp~n", [LoopInCatchOnly]),

    io:format("TryCatchThrow:~tp TryCatchError:~tp TryCatchExit:~tp~n", [TryCatchThrow, TryCatchError, TryCatchExit]),
    io:format("TryCatchStacktraceThrow:~tp TryCatchStacktraceError:~tp TryCatchStacktraceExit:~tp~n", [TryCatchStacktraceThrow, TryCatchStacktraceError, TryCatchStacktraceExit]),
    io:format("CatchStacktraceThrow:~tp CatchStacktraceError:~tp CatchStacktraceExit:~tp~n", [CatchStacktraceThrow, CatchStacktraceError, CatchStacktraceExit]).

loop_only(0, _, _, _) -> ok;
loop_only(Times, Class, R, S) ->
    make_an_exception(Class),
    loop_only(Times - 1, Class, R, S).

loop_in_try_catch_only(0, _, _) -> ok;
loop_in_try_catch_only(Times, Class, R) ->
    try
        make_an_exception(Class),
        loop_in_try_catch_only(Times - 1, Class, R)
    catch
        Class:Reason ->
            loop_in_try_catch_only(Times - 1, Class, Reason)
    end.

loop_in_try_catch_stacktrace_only(0, _, _, _) -> ok;
loop_in_try_catch_stacktrace_only(Times, Class, R, S) ->
    try
        make_an_exception(Class),
        loop_in_try_catch_stacktrace_only(Times - 1, Class, R, S)
    catch
        Class:Reason:Stacktrace ->
            loop_in_try_catch_stacktrace_only(Times - 1, Class, Reason, Stacktrace)
    end.

loop_in_catch_only(0, _) -> ok;
loop_in_catch_only(Times, Class) ->
    catch make_an_exception(Class),
    loop_in_catch_only(Times - 1, Class).

loop_try_catch(0, _, _) -> ok;
loop_try_catch(Times, Class, _) ->
    try
        make_an_exception(Class)
    catch
        Class:Reason ->
            loop_try_catch(Times - 1, Class, Reason)
    end.

loop_try_catch_stacktrace(0, _, _, _) -> ok;
loop_try_catch_stacktrace(Times, Class, _, _) ->
    try
        make_an_exception(Class)
    catch
        Class:Reason:Stacktrace ->
            loop_try_catch_stacktrace(Times - 1, Class, Reason, Stacktrace)
    end.

loop_catch(0, _) -> ok;
loop_catch(Times, Class) ->
    catch make_an_exception(Class),
    loop_catch(Times - 1, Class).

make_an_exception(Class) ->
    case Class of
        throw -> erlang:throw(ladies);
        error -> erlang:error(ladies);
        exit -> erlang:exit(ladies);
        _ -> nothing_wrong
    end.

时间

不带stacktrace

LoopTime
None6161
TryCatch130163
TryCatchStacktrace31760
CatchStacktrace6142

携带stacktrace

ExceptionThrowErrorExit
TryCatch766897387573508
TryCatchStacktrace555028557794547894
CatchStacktrace729097362972771

结论

在不发生异常的情况下

  • 频繁进入try/catch性能很差。
  • 直接catch性能反而没什么损失。

在发生异常的情况下

  • 异常比正常返回慢了十几倍。
  • 带stacktrace的try/catch性能是最差的, 比其他两种方法相差近8倍。

所以, 异常能不用就不用, 哪怕在JIT预热后还是挺慢的。

发表评论