erlang常規(guī)面試題
- 基礎
- 消息發(fā)送
基礎相關
OTP相關
- gen_server:cast和erlang:send()都可以向指定進程發(fā)消息,有什么區(qū)別?
- gen_server:cast調(diào)用的就是erlang:send()函數(shù),消息為{'$gen_cast',Request},但是加上了no_connect.如果沒有連上,那么返回false
- en_server遠程call一個節(jié)點方法的過程?
- 回答者需要知道empd的概念及其相關過程。
- gen_server:call({Name,Node},Request)可以call遠程節(jié)點的進程,和call(Node, Module, Function, Args)有什么區(qū)別?
- rpc:call是調(diào)用遠程節(jié)點的rex進程來做事情,gen_server:call可以選中遠程節(jié)點的任意進程做事情
- rpc:call的內(nèi)部實現(xiàn)就是gen_server:call({Name,Node},Request),只不過NAME為rex
時間函數(shù)相關
- erlang:now()和os:timestamp()
- erlang:now()獲取的是erlang虛擬機時鐘,os:timestamp()獲取的是操作系統(tǒng)時間。
- 假設start_timer(1000), 這個時候跳快系統(tǒng)時間,會提前收到消息嗎?
- 不會。start_timer/3用的是虛擬機內(nèi)部時間
- erlang:send_after和erlang:start_timer的區(qū)別
- 主要是TimerRef,超時消息進入郵箱,這個時候用TimerRef來匹配誰來發(fā)的,以便做處理。
- 是否了解otp 18中新引入的時間函數(shù)
數(shù)據(jù)類型
- ref()有是什么?什么用?
- ref()就是一個erlang中的基礎數(shù)據(jù)類型,就是用來唯一表示(erlang只能保證基本100%)和比較的。
- A發(fā)送消息的時候B,加一個ref,在receive中用這個ref來高效和指定匹配B返回的消息
ets表
- write_concurrency和read_concurrency是用使得ets表支持讀和寫并發(fā)控制的嗎?
- 不是。ets原生就支持并發(fā)控制,通過原子操作來實現(xiàn)。就是說,單個ets表的讀寫都是原子的。他們是用來提升讀寫性能的,代價是額外內(nèi)存
進程相關
- 不使用io或者lager:info,如何確定進程受到的消息和發(fā)出的消息?
- 回答者需要知道erlang:dbg模塊,trace相關的知識。如果知道火焰圖相關知識,更好
- Pid的那3位數(shù)字<A,B,C>代表著什么
- A, 對應是哪一個節(jié)點 (0 代表是本地節(jié)點 ,其它數(shù)字代表遠程節(jié)點)
- B, 低15字節(jié)代表進程唯一記數(shù)(一個進程表的索引)
- C, 16~18字節(jié)也是進程唯一記數(shù)(和B一樣)
消息發(fā)送
簡要說明消息兩個進程的傳遞過程
selective match相關
- 什么是selective match
只接受感興趣的消息,代碼顯式寫明
<pre>
receive
{'tag',Tag} -> do_something();
...
end
</pre> - selective match潛在問題和erlang系統(tǒng)如何對此優(yōu)化
- 潛在問題:需要遍歷郵箱,如果郵箱消息數(shù)目過多,可能會耗費時間
- 優(yōu)化:發(fā)送make_ref(), 在遍歷消息的時候,erlang系統(tǒng)會自動跳過在這個ref創(chuàng)建之前接受的消息
<pre>
optimized(Pid) ->
Ref = make_ref(),
Pid ! {self(), Ref, hello},
receive
{Pid, Ref, Msg} ->
io:format("pn", [Msg])
end.
</pre>
receive的理解
- receive會檢查遍歷進程的郵箱一次(請注意是一次),根據(jù)guide做匹配;
- 一旦匹配到一個消息,執(zhí)行對應的guide的代碼,去掉郵箱中對應的消息;之后掛起;也就是說,匹配到滿足條件的,就會立刻停止匹配過程,等待下一次匹配
- 什么時候觸發(fā)下一次匹配?有新消息來的時候
- 如果不加after,只有當匹配guide之后,才能往下走;否則,計算收到消息,也會阻塞在原地,等待下一次消息到來,再次啟動匹配。也就是說,下面
<pre>
init() ->
Pid = spawn(fun() -> init_wait() end),
register(test, Pid).
init_wait() ->
io:format("expected receive: foo"),
receive //here1
foo -> foo
end,
io:format("expected receive: bar"),
receive
bar -> bar
end,
io:format("init_wait: finish").
</pre>
這里一直會阻塞在here1,除非進程受到'foo'這個消息;就算受到其它消息,也不會往下走