Erlang processes DONT share memories
erlang processes是小型的erlang VM。這是erlang語言層級的process,不是OS層級的,所以在任何erlang VM上都能保持一致行為。兩個erlang processes之間不share memory,這很合理,連單一erlang process之內都不能change memory data了,何況是share給另一個erlang process!
這讓scalability變得很容易,因為彼此processes是獨立的,所以增加workload就可以簡單地增加人力(processes)來因應。
不分享記憶,就不用保護記憶,就沒有lock & keys。
沒有lock & keys,就不會有一大堆相關的錯誤,特別容易出現在concurrent programming。
Error Detection
既然processes沒有share memory,怎麼辦法溝通?靠send messages。(erlang是一個pure message-passing language),不過messages有沒有被其他人收到或是處裡的話,還要再send messages去詢問對方 (除非對方send ACK回來)。
另外一個process死掉會broadcast出來給其他processes知道,某個跟他“link關聯"的process會接手 (稱為linked pair)。這樣就能做error detection。
Concurrent Primitives
Erlang concurrent program只需要以下三個primitive operations就可以構成一個concurrent program:
1. spawn: 產生一個erlang process。如果要refer到這個產生的process的話,就靠此 operation回傳的Pid。
另一個版本為:
2. send message: 傳送message 給某一個Pid。比較特別的是 ! 是send operator。
此operator "似乎" (還待證實)會回傳送出去的message,所以我們可以chaining 這個operators:
Pid1 ! Pid2 ! … ! Msg ,代表對Pid1 Pid2 ... 送出Msg 這個messageㄡ
3. receive:
如果想要等待某個message,就可以用此operation配合上pattern-matching:
receive的語法如下:
Process Example
先寫一個process專門計算面積的:-module(area_server0).-export([loop/0]). loop() -> receive {rectangle, Width, Ht} -> io:format("Area of rectangle is ~p~n",[Width * Ht]), loop(); {square, Side} -> io:format("Area of square is ~p~n", [Side * Side]), loop() end.
這個server process簡單來說就是等待message,如果match {rectangle,W,H} 或是 {square, S} pattern的話,就印出面積,然後等待下一次的message進來。
我們可以在Erlang console spawn此server process以及其receiver:
6> Pid = spawn(area_server0, loop, []).
<0.64.0>
有了Pid之後,用 ! operator來傳送符合pattern的message給Pid:
9> Pid ! {square, 10}.
Area of square is 100
{square,10}
這樣就完成了一次簡單的messaging, 可以看到console另外也印出了message,這表示 ! operator的確是回傳message (書上是說 Pid ! Msg被定義成Msg),有待查證到底哪一個對。
Client-Server Example
真的要變成一個client-server架構的話,至少還缺了client的Pid,因為沒有這個server等於沒辦法將計算結果回傳給client。改寫server如下:
-module(area_server0).-export([loop/0]). loop() -> receive {FromPid, {rectangle, Width, Ht}} -> FromPid ! Width * Ht, loop(); {FromPid, {square, Side}} -> FromPid ! Side * Side, loop() end.
可以看到pattern matching改了,而且server process也回送message 給FromPid,所以我們的client也必須要是一個Erlang process才能收到server的message,我們先把server延伸成有client能力(能夠發request也能等待回應):
rpc(ToPid, Request) -> ToPid ! {self(), Request}, receive {Response} -> Response end.
如果發以下指令:
1> Pid = spawn(server, loop, []).
<0.57.0>
2> server:rpc(Pid, {square, 10}).
是可以回傳面積的,可是在IntelliJ Erlang plugin的console不知道為什麼出不來,不過在一班的erlang console是可以的。
client如何只回應特定的server?
pattern matching這邊發揮美麗的特性:rpc(ToPid, Request) -> ToPid ! {self(), Request}, receive {ToPid, Response} -> io:format("Area of rectangle is from ~p, response = ~p ~n",[ToPid, Response]), Response end. loop() -> receive {FromPid, {rectangle, Width, Ht}} -> FromPid ! {self(), Width * Ht}, loop(); {FromPid, {square, Side}} -> FromPid ! {self(), Side * Side}, loop() end.
沒有留言:
張貼留言