You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Erlang select receive机制细节及实操结果不符问题咨询

Erlang 选择性接收(select receive)机制实现差异说明

核心差异原因

你复现结果和旧文章结论不一致的核心原因是Erlang/OTP版本迭代优化了内部实现:2010年相关文章的结论仅适用于R14B及更早的旧版本Erlang,OTP 17之后官方重写了选择性接收的逻辑,你使用的OTP 21已经是优化后的实现版本。

旧版本实现逻辑(R14B及更早)

旧版本确实遵循你看到的结论:

  • 执行receive匹配时,进程会遍历消息队列,将不匹配的消息临时移动到独立的「保存队列」
  • 直到匹配到目标消息、或receive触发超时后,再把保存队列里的所有消息移回主消息队列
  • 这个阶段用process_info(..., messages)查询时,看不到被移到保存队列的消息,和你测试的结果不同

新版本实现逻辑(OTP 17及以后,包含你用的OTP 21)

官方针对旧版本消息反复移动的性能问题做了优化,不再实际移动消息:

  • 进程扫描消息队列找匹配项时,只会用指针标记已经扫描过的不匹配消息位置
  • 新消息到达后,直接从上次标记的位置往后扫描即可,不需要挪动任何已收到的消息
  • 所有未消费的消息始终留在主消息队列中,所以你用process_info查询时,始终能看到c、d两条消息,队列长度也始终为2,和你测试的结果完全吻合

你的测试场景对应说明

你的测试操作符合新版本实现的正常表现:

% shell1操作
(aaa@HW0003727)1> register(shell, self()).
true
(aaa@HW0003727)2> shell ! c, shell ! d.
d
(aaa@HW0003727)3> process_info(whereis(shell),messages).
{messages,[c,d]}.
(aaa@HW0003727)4> receive a -> 1; b -> 2 end.

% shell2操作
(aaa@HW0003727)1> process_info(whereis(shell),messages).
{messages,[c,d]}
(aaa@HW0003727)2> process_info(whereis(shell)).          
[{registered_name,shell},
 {current_function,{prim_eval,'receive',2}},
 {initial_call,{erlang,apply,2}},
 {status,waiting},
 {message_queue_len,2},
 {links,[<0.113.0>]},
 {dictionary,[]},
 {trap_exit,false},
 {error_handler,error_handler},
 {priority,normal},
 {group_leader,<0.112.0>},
 {total_heap_size,4212},
 {heap_size,1598},
 {stack_size,30},
 {reductions,13906},
 {garbage_collection,[{max_heap_size,#{error_logger => true,kill => true,size => 0}},
                      {min_bin_vheap_size,46422},
                      {min_heap_size,233},
                      {fullsweep_after,65535},
                      {minor_gcs,1}]},
 {suspending,[]}]

你执行receive a -> 1; b -> 2 end.后进程挂起等待匹配消息,因为没有匹配项,两条不匹配的消息没有被移动,所以shell2查询时始终能看到完整的消息队列,属于新版本的正常表现。


内容的提问来源于stack exchange,提问作者Caker Pang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 11:45:03