检查Erlang中的活动计时器

Ale*_*nov 10 erlang

有一个简单的方式来获得所有当前正在等待计时器的名单开始erlang:send_after,erlang:apply_after等在二郎山?

Zed*_*Zed 6

出于调试目的,您可以使用dbg:).

首先创建一个ets表,它将存储所有计时器引用.

1> ets:new(timer_dbg, ['public', 'named_table', 'bag']).
timer_dbg
Run Code Online (Sandbox Code Playgroud)

然后创建一个dbg处理函数,它检查从erlang:send_after返回的调用,并将返回的计时器引用保存到表中

2> Fun = fun({'trace', _Pid, 'return_from', {erlang, send_after, 3}, Ref}, []) ->
2>           ets:insert(timer_dbg, {Ref}), [];
2>          (_Msg, []) ->
2>           []
2>       end.
#Fun<erl_eval.12.113037538>
Run Code Online (Sandbox Code Playgroud)

将该函数设置为跟踪处理程序.还可以在呼叫上erlang:send_after()启用所有进程的匹配

3> dbg:tracer('process', {Fun, []}).
{ok,<0.35.0>}
4> dbg:p('all', 'c').
{ok,[{matched,nonode@nohost,26}]}
5> dbg:tpl(erlang, send_after, [{'_', [], [{'return_trace'}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}
Run Code Online (Sandbox Code Playgroud)

做一些测试电话 erlang:send_after()

6> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.43>
7> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.47>
8> erlang:send_after(1000, self(), {}).
#Ref<0.0.0.51>
Run Code Online (Sandbox Code Playgroud)

最后检查表是否包含这些引用:

9> ets:tab2list(timer_dbg).
[{#Ref<0.0.0.51>},{#Ref<0.0.0.43>},{#Ref<0.0.0.47>}]
Run Code Online (Sandbox Code Playgroud)

这样,您将存储由任何进程调用创建的所有计时器引用erlang:send_after().您可以映射它们erlang:read_timer()以过滤活动计时器.

您可以send_after以类似的方式跟踪呼叫.也可以匹配cancel_timer并手动删除表中取消的引用.

此外,如果您没有消息密集型应用程序,则应该能够匹配这些计时器触发的消息和/或函数,并从列表中删除过期的引用.


use*_*720 5

这是一个 hack,但使用:ets:tab2list(timer_tab)。对于两个计时器,它包含:

  ets:tab2list(timer_tab).                                            
[{{1288384968923398,#Ref<0.0.0.30>},
  timeout,
  {erlang,integer_to_list,[23]}},
 {{23334621698390115688,#Ref<0.0.0.189>},
  timeout,
  {erlang,integer_to_list,[23]}}]
Run Code Online (Sandbox Code Playgroud)

  • 它仅对 `timer` 模块定时器有用,但不适用于使用 `erlang:send_after`、`erlang:apply_after` 创建的定时器 (2认同)