Note: Since R14A, a new optimization has been added to Erlang's compiler. It simplifies selective receives in very specific cases of back-and-forth communications between processes. An example of such a function is
optimized/1
in multiproc.erl.To make it work, a reference (
make_ref()
) has to be created in a function and then sent in a message. In the same function, a selective receive is then made. If no message can match unless it contains the same reference, the compiler automatically makes sure the VM will skip messages received before the creation of that reference.Note that you shouldn't try to coerce your code to fit such optimizations. The Erlang developers only look for patterns that are frequently used and then make them faster. If you write idiomatic code, optimizations should come to you. Not the other way around.
32 optimized(Pid) -> 33 Ref = make_ref(), 34 Pid ! {self(),Ref,hello}, 35 receive 36 {Pid,Ref,Msg} -> 36 io:format("~p~n", [Msg]) 37 end.
24 normal() -> 25 receive 26 {_, Message} -> 27 [Message | normal()] 28 after 0 -> 29 [] 30 end. {function, normal, 0, 13}. {label,12}. {line,[{location,"msg.erl",24}]}. {func_info,{atom,msg},{atom,normal},0}. {label,13}. {allocate_zero,1,0}. {line,[{location,"msg.erl",25}]}. {label,14}. {loop_rec,{f,16},{x,0}}. {test,is_tuple,{f,15},[{x,0}]}. {test,test_arity,{f,15},[{x,0},2]}. {get_tuple_element,{x,0},1,{y,0}}. remove_message. {line,[{location,"msg.erl",27}]}. {call,0,{f,13}}. {test_heap,2,1}. {put_list,{y,0},{x,0},{x,0}}. {deallocate,1}. return. {label,15}. {loop_rec_end,{f,14}}. {label,16}. timeout. {move,nil,{x,0}}. {deallocate,1}. return.
下面,我们对比一下有make_ref版本的代码:
32 optimized(Pid) -> 33 Ref = make_ref(), 34 Pid ! {self(),Ref,hello}, 35 receive 36 {Pid,Ref,Msg} -> 36 io:format("~p~n", [Msg]) 37 end. {function, optimized, 1, 18}. {label,17}. {line,[{location,"msg.erl",33}]}. {func_info,{atom,msg},{atom,optimized},1}. {label,18}. {allocate_zero,2,1}. {move,{x,0},{y,1}}. {line,[{location,"msg.erl",34}]}. {recv_mark,{f,19}}. {call_ext,0,{extfunc,erlang,make_ref,0}}. {test_heap,4,1}. {bif,self,{f,0},[],{x,1}}. {move,{x,0},{y,0}}. {put_tuple,3,{x,2}}. {put,{x,1}}. {put,{y,0}}. {put,{atom,hello}}. {move,{x,2},{x,1}}. {move,{y,1},{x,0}}. {line,[{location,"msg.erl",35}]}. send. {line,[{location,"msg.erl",36}]}. {recv_set,{f,19}}. {label,19}. {loop_rec,{f,21},{x,0}}. {test,is_tuple,{f,20},[{x,0}]}. {test,test_arity,{f,20},[{x,0},3]}. {get_tuple_element,{x,0},0,{x,1}}. {get_tuple_element,{x,0},1,{x,2}}. {get_tuple_element,{x,0},2,{x,3}}. {test,is_eq_exact,{f,20},[{x,1},{y,1}]}. {test,is_eq_exact,{f,20},[{x,2},{y,0}]}. remove_message. {test_heap,2,4}. {put_list,{x,3},nil,{x,1}}. {move,{literal,"~p~n"},{x,0}}. {line,[{location,"msg.erl",38}]}. {call_ext_last,2,{extfunc,io,format,2},2}. {label,20}. {loop_rec_end,{f,19}}. {label,21}. {wait,{f,19}}.