Erlang 的并發(fā)編程需要遵循以下基本原則或過程。
列表包括以下原則:
piD = spawn(Fun)
創(chuàng)建一個評估 Fun 的新并發(fā)進程。新進程與調用方并行運行。一個實例如下-
-module(helloworld). -export([start/0]). start() -> spawn(fun() -> server("Hello") end). server(Message) -> io:fwrite("~p",[Message]).
上面程序的輸出是-
“Hello”
用標識符 Pid 向進程發(fā)送消息。消息發(fā)送是異步的。發(fā)送者不會等待,而是繼續(xù)它正在做的事情?!埃 环Q為發(fā)送運算符。
一個實例如下-
-module(helloworld). -export([start/0]). start() -> Pid = spawn(fun() -> server("Hello") end), Pid ! {hello}. server(Message) -> io:fwrite("~p",[Message]).
接收已發(fā)送到進程的消息。它具有以下語法-
receive Pattern1 [when Guard1] -> Expressions1; Pattern2 [when Guard2] -> Expressions2; ... End
當消息到達該進程時,系統(tǒng)會嘗試將其與Pattern1匹配(可能有Guard 1)。如果成功,則對Expressions1求值。如果第一個模式不匹配,則嘗試使用Pattern2,依此類推。如果沒有任何一個模式匹配,則保存該消息以供以后處理,然后該過程等待下一條消息。
以下程序顯示了使用全部3個命令的整個過程的示例。
-module(helloworld). -export([loop/0,start/0]). loop() -> receive {rectangle, Width, Ht} -> io:fwrite("Area of rectangle is ~p~n" ,[Width * Ht]), loop(); {circle, R} -> io:fwrite("Area of circle is ~p~n" , [3.14159 * R * R]), loop(); Other -> io:fwrite("Unknown"), loop() end. start() -> Pid = spawn(fun() -> loop() end), Pid ! {rectangle, 6, 10}.
關于上述程序,需要注意以下幾點:
loop函數(shù)具有接收端循環(huán)。因此,當消息被發(fā)送時,它將被接收端循環(huán)處理。
生成一個新進程,該進程將轉到循環(huán)函數(shù)。
通過 Pid! message 命令將消息發(fā)送到產生的進程。
上面程序的輸出是-
Area of the Rectangle is 60
并發(fā)地,重要的是確定系統(tǒng)上允許的最大進程數(shù)。然后,您應該能夠了解系統(tǒng)上可以同時執(zhí)行多少個進程。
讓我們看一個示例,該示例如何確定系統(tǒng)上可以執(zhí)行的最大進程數(shù)。
-module(helloworld). -export([max/1,start/0]). max(N) -> Max = erlang:system_info(process_limit), io:format("Maximum allowed processes:~p~n" ,[Max]), statistics(runtime), statistics(wall_clock), L = for(1, N, fun() -> spawn(fun() -> wait() end) end), {_, Time1} = statistics(runtime), {_, Time2} = statistics(wall_clock), lists:foreach(fun(Pid) -> Pid ! die end, L), U1 = Time1 * 1000 / N, U2 = Time2 * 1000 / N, io:format("Process spawn time=~p (~p) microseconds~n" , [U1, U2]). wait() -> receive die -> void end. for(N, N, F) -> [F()]; for(I, N, F) -> [F()|for(I+1, N, F)]. start()-> max(1000), max(100000).
在任何具有良好處理能力的機器上,上述兩個最大函數(shù)都會通過。下面是上述程序的一個示例輸出。
Maximum allowed processes:262144 Process spawn time=47.0 (16.0) microseconds Maximum allowed processes:262144 Process spawn time=12.81 (10.15) microseconds
有時,receive語句可能會永遠等待一條永遠不會出現(xiàn)的消息。這可能有很多原因。例如,我們的程序中可能存在邏輯錯誤,或者要向我們發(fā)送消息的進程在發(fā)送消息之前可能已經崩潰。為了避免這個問題,我們可以在receive語句中添加一個超時。這將設置進程等待接收消息的最長時間。
以下是指定了超時的接收消息的語法
receive Pattern1 [when Guard1] -> Expressions1; Pattern2 [when Guard2] -> Expressions2; ... after Time -> Expressions end
最簡單的實例是創(chuàng)建一個sleeper函數(shù),如下面的程序所示。
-module(helloworld). -export([sleep/1,start/0]). sleep(T) -> receive after T -> true end. start()-> sleep(1000).
上述代碼在實際退出之前將休眠1000毫秒。
Erlang中的每個進程都有一個關聯(lián)的郵箱。當您向該進程發(fā)送消息時,該消息將放入郵箱中。僅當程序評估接收語句時,才檢查此郵箱。
以下是“選擇性接收”語句的一般語法。
receive Pattern1 [when Guard1] -> Expressions1; Pattern2 [when Guard1] -> Expressions1; ... after Time -> ExpressionTimeout end
這就是上面的接收語句的工作方式-
當我們輸入一個receive語句時,我們將啟動一個計時器(但前提是表達式中存在一個after節(jié))。
以郵箱中的第一封郵件,并嘗試使其與Pattern1,Pattern2等匹配。如果匹配成功,將從郵箱中刪除該郵件,并評估模式后面的表達式。
如果receive語句中的任何模式都不匹配郵箱中的第一條消息,則將從郵箱中刪除第一條消息并將其放入“保存隊列”。然后嘗試郵箱中的第二條消息。重復此過程,直到找到匹配的消息或檢查了郵箱中的所有消息為止。
如果郵箱中的所有郵件都不匹配,則該過程將被掛起,并將在下次將新郵件放入郵箱中時重新安排執(zhí)行時間。請注意,當收到新消息時,保存隊列中的消息將不重新匹配;僅匹配新消息。
一旦匹配了一條消息,所有放入保存隊列的消息就會按照到達過程的順序重新輸入到郵箱中。如果設置了計時器,則將其清除。
如果在等待消息時計時器已過去,請評估表達式ExpressionsTimeout并將所有保存的消息按到達過程的順序放回郵箱。