检查 Erlang 中的活动计时器

发布于 2024-09-29 23:09:32 字数 88 浏览 2 评论 0原文

有没有一种简单的方法可以获取 Erlang 中以 erlang:send_after 、 erlang:apply_after 等启动的所有当前等待计时器的列表?

Is there a simple way to get a list of all currently waiting timers started with erlang:send_after, erlang:apply_after, etc. in Erlang?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心奴独伤 2024-10-06 23:09:33

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

首先创建一个 ets 表来存储所有计时器引用。

1> ets:new(timer_dbg, ['public', 'named_table', 'bag']).
timer_dbg

然后创建一个 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>

将函数设置为跟踪处理程序。还可以在所有进程上对 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}]}

() 进行一些测试调用

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>

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

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

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

您可以以类似的方式跟踪对 send_after 的调用。还可以匹配 cancel_timer 并手动从表中删除已取消的引用。

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

For debugging purposes you can use dbg :).

First create an ets table which will store all timer references.

1> ets:new(timer_dbg, ['public', 'named_table', 'bag']).
timer_dbg

Then create a dbg handler function, which checks for calls returning from erlang:send_after, and saves the returned timer reference to the table

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>

Set the function as trace handler. Also enable matching on the call to erlang:send_after() on all processes

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}]}

Make some test calls to 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>

Finally check that the table does contain those references:

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

This way you will store all timer references ever created by any process ever calling erlang:send_after(). You can map them over erlang:read_timer() to filter the alive timers.

You can trace calls to send_after in a similar manner. It is also possible to match on cancel_timer and manually remove the cancelled references from the table.

Also, if you don't have a message-intensive application, you should be able to match on messages and/or functions triggered by those timers, and remove the expired references from the list.

还给你自由 2024-10-06 23:09:33

这是一个 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]}}]

thats a hack but use: ets:tab2list(timer_tab). For two timers it holds:

  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]}}]
杯别 2024-10-06 23:09:33

查看 erl_bif_timer.c 中的代码我认为故障转储是唯一可以找到所有刚刚活动的 BIF 计时器列表的地方。 :-)

Looking at the code in erl_bif_timer.c I think crash dump is the only place where you can find a list of all BIF timers which were just active. :-)

愛放△進行李 2024-10-06 23:09:33

今天我也遇到了跟踪计时器的同样必要性。

它正在生产中,所以我不想使用 dbg。这些是 erlang:timers 所以我之前的解决方案是无用的。

相反,我分析了 binary_to_list(erlang:system_info(info)) 中的 nbif_timer 参数。

我相信(尚未确认),它报告了为计时器分配的内存。在我的 x64 系统上,这将是 17 个字,每 8 个字节 = 136 个字节。

监视该值可以清楚地显示系统何时设置大量计时器。

享受。

I run into the same necessity of tracking timers today.

It is on production, so I do not want to use dbg. These are erlang:timers so my previous solution is useless.

Instead I analysed nbif_timer parameter from binary_to_list(erlang:system_info(info)).

I believe (have not confirmed yet), it reports memory allocated for timers. On my system x64 it would be 17 words of 8 bytes = 136 bytes.

Monitoring this value clearly shows when system sets high number of timers.

enjoy.

遥远的绿洲 2024-10-06 23:09:33

您可以保存 send_after、aply_after 等返回的引用,并使用 erlang:read_timer 检查它是否仍在等待(如果计时器已被取消或不再等待,则 read_timer 返回 false)

you could save the references returned by send_after, aply_after etc and use erlang:read_timer to check if it is still waiting (read_timer returns false if the timer has been canceled or isn't waiting anymore)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文