Erlang基礎知識集錦

http://wenku.baidu.com/link?url=or-8mkUYUM0uVeqCYESGe93YIlh2IDLP7lFOwRlwr8Syf3PeHbwJC5DPCErs4NFrb1p4I16eJuHIIFG_tR_jdYGoL5MsJX0YEjdeUmKjkTGcss

一、and or 和andalso orelse的區別node

and和or會計算兩邊的表達式,而andalso和orelse的求值採用短路機制,好比exp1 andalso exp2,當exp1返回false以後,就不會去求值 
exp2,而是直接返回false,而exp1 and exp2會對exp1和exp2都進行求值,or與orelse也相似。git

二、在Erlang中小於等因而用=<表示,而不是通常語言中的<=語法,一樣,不等於都是用/號,而不是!,好比/=、=/=。shell

三、Erlang的保留字有:編程

after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse query receive rem try when xor數組

基本都是些用於邏輯運算、位運算以及特殊表達式的符號服務器

四、模塊的預約義屬性: 
-module(Module).    聲明模塊名稱,必須與文件名相同 
-export(Functions).   指定向外界導出的函數列表 
-import(Module,Functions).   引入函數,引入的函數能夠被看成本地定義的函數使用 
-compile(Options).     設置編譯選項,好比export_all 
-vsn(Vsn).         模塊版本,設置了此項,能夠經過beam_lib:version/1 獲取此項信息 
能夠經過-include和-include_lib來包含文件,二者的區別是include-lib不能經過絕對路徑查找文件,而是在你當前Erlang的lib目錄進行查找。cookie

五、宏,定義常量或者函數等等,語法以下: 
-define(Const, Replacement). -define(Func(Var1,...,VarN), Replacement). 
使用的時候在宏名前加個問號?,好比?Const,Replacement將插入宏出現的位置。系統預約義了一些宏: 
?MODULE 表示當前模塊名 
?MODULE_STRING 同上,可是以字符串形式 
?FILE 當前模塊的文件名 
?LINE 調用的當前代碼行數 
?MACHINE 機器名 
Erlang的宏與C語言的宏很類似,一樣有宏指示符,包括:網絡

-undef(Macro).
取消宏定義
-ifdef(Macro).
當宏Macro有定義的時候,執行如下代碼
-ifndef(Macro).
同上,反之
-else.
接在ifdef或者ifndef以後,表示不知足前者條件時執行如下代碼 
-endif.
if終止符

假設宏-define(Square(X),X*X).用於計算平方,那麼??X將返回X表達式的字符串形式,相似C語言中#arg併發

 

聲明:此文檔只做爲對erlang的認知之用,若是須要學習並使用erlang請系統學習介紹erlang的書。

  1. 1.       簡介

l  Erlang是一個並行編程語言和運行時系統,最初由愛立信(Ericsson)於1987年爲電信行業所開發。1998年愛立信在改良的MPL(Mozilla Public License)許可下將Erlang發佈於開源社區。

l  Erlang是:

a)   一種「小衆」語言。

b)   一種函數式語言 (變量只能賦值一次)。

c)   一種動態類型語言(變量類型在運行時決定,代碼須要編譯後才能執行,與Python,Ruby等不同)。

d)   一種強類型語言。

e)   一種面向併發(Concurrency Oriented)的語言。

  1. 2.       特性

l  併發性 - Erlang支持超大量級的併發線程,而且不須要操做系統具備併發機制。

l  分佈式 - 一個分佈式Erlang系統是多個Erlang節點組成的網絡(一般每一個處理器被做爲一個節點)。

l  健壯性 - Erlang具備多種基本的錯誤檢測能力,它們可以用於構建容錯系統。

l  軟實時性- Erlang支持可編程的「軟」實時系統,使用了遞增式垃圾收集技術。

l  熱代碼升級-Erlang容許程序代碼在運行系統中被修改。舊代碼能被逐步淘汰然後被新代碼替換。在此過渡期間,新舊代碼是共存的。

l  遞增式代碼裝載-用戶可以控制代碼如何被裝載的細節。

l  外部接口-Erlang進程與外部世界之間的通信使用和在Erlang進程之間相同的消息傳送機制。

3. 數據類型

  1.  
  2.  
  3.  

3.1.  變量

3.1.1. 在erlang中的變量只能被賦值一次,變量第一個字母要是大寫的。

3.1.2. 符號」=」是值類型匹配操做(帶有賦值的意思)。(pattern matching)

3.1.3. 在erlang中變量是不可變的,也沒有共享內存的概念,也沒有鎖。

3.2.  浮點數

3.2.1. 整數除法示例: 4 div 2。

3.2.2. 求餘示例:     5 rem 2。

3.2.3. 「/」永遠返回浮點數。

3.3.  Atoms(原子)

3.3.1. Atoms表示不一樣的非數字常量值。

3.3.2. 示例: Xss = 'Asss'。 

 

  1.  
  2.  

3.4.  元組

3.4.1. 將若干個以逗號分隔的值用一對大括號括起來就造成了一個元組。

3.4.2. 元組示例: Person = {person, {name, joe}, {height, 1.83}, {footsize, 42}}.

3.4.3. 從元組中提取數據:

Point = {point, 10, 45}.

{point, X, Y} = Point.( pattern match)

此後X=10, Y=45.

 

3.5.  列表

3.5.1. 將若干個以逗號分隔的值用一對方括號括起來,就造成了一個列表。

3.5.2. 示例: ThingsToBuy = [{apple, 10}, {pear, 6}, {milk, 3}].

3.5.3. 列表中的第一個元素叫作列表頭,剩下的部分叫作列表尾。通常來講列表頭能夠是任何東西,列表尾常常是一個列表。

3.5.4. 訪問列表頭元素是一個很是高效的操做。

3.5.5. 從列表中解析元素:

ThingsToBuy1 = [{oranges, 4}, {newspaper, 1}|ThingsToBuy].

[Buy1|ThingsToBuy2] = ThingsToBuy1.

此後:ThingsToBuy1 = [{oranges,4},{newspaper,1},{apple,10},{pear,6},{milk,3}].

Buy1 = {oranges,4}.

ThingsToBuy2 = [{newspaper,1},{apple,10},{pear,6},{milk,3}].

 

3.6.  字符串

3.6.1. 在erlang中沒有字符串,字符串僅僅是整數列表。用雙引號將一串字符括起來就是一個字符串。

3.6.2. 示例:

Name = "Hello".

5>I = $s.

115

8> [I-32, $u, $r, $p, $r, $i, $s, $e].

"Surprise"

4. Erlang基本語法

  1.  

4.1.  模塊

  1. 3.  
  2. 4.  

4.1.  

4.1.1. Erlang源文件是以.erl作爲擴展名的,頭文件是以.hrl作爲擴展名的。

4.1.2. 要運行一個模塊,首先要編譯它,編譯之後的文件是以.beam作爲擴展名的。文件編譯命令:c(Modulename).

4.1.3. 改變erlang的工做目錄

在操做系統用戶文件夾下找到目前登陸用戶的文件夾在其中創建一個.erlang文件夾,在這個文件中寫上:c:cd("you work dir"). 重啓erlang shell就改變了工做路徑。

4.1.4. 在erlang中符號的使用:

逗號(,)用來分隔函數調用,數據構造器(列表元組中的逗號)以及模式中的參數。

句號(.)(後面跟一個空白符號)用來在shell中分隔完整的函數和表達式。

分號(;)用來分隔子句,在如下幾種狀況下都會用到子句:分段的函數定義,case子句, if語句, try…catch語句, 以及receive表達式。

4.1.5. 調用模塊中的方法:Modules:ExportFunc(…)

 

4.2.  匿名函數(fun關鍵字)

4.2.  

4.2.1. 使用示例:

1> Hypot = fun(X, Y) -> math:sqrt(X*X + Y*Y) end.

#Fun<erl_eval.12.113037538>

2> Hypot(3, 4).

5.0

 

4.2.2. 匿名函數能夠做爲函數的參數,而且做爲函數的返回值。

4.2.3. 定義本身的抽象控制流程:

for(Max, Max, F) -> [F(Max)];

for(I, Max, F)   -> [F(I)|for(I+1, Max, F)].

 

4.3.  簡單列表處理

  1. 1.  
  2. 2.  
  3. 3.  
  4. 4.  

4.1.  

4.2.  

4.3.  

4.3.  

4.3.1. map函數示例:

map(_, []) -> [];

map(F, [H|T]) ->[F(H)|map(F, T)].

1>  L = [1,2,3,4,5].

[1,2,3,4,5]

map(fun(X) -> 2*X end, L).

輸出:[2,4,6,8].

4.4.  列表理解

4.4.  

4.4.1. 示例:

1> L = [1,2,3,4].

[1,2,3,4]

2> [2*X || X <- L].

[2,4,6,8]

         

            1> Buy = [{oranges, 4}, {newspaper, 1}, {apples, 10}, {pears, 6}, {milk, 3}].

[{oranges,4},{newspaper,1},{apples,10},{pears,6},{milk,3}]

2> [{Name, 2*Number} || {Name, Number} <- Buy].

[{oranges,8},{newspaper,2},{apples,20},{pears,12},{milk,6}]

 

 

4.5.  算數表達式(以及優先級)

參見下圖:

 

 

4.6.   Guard

4.5.  

4.6.  

4.6.1. Guard是一種強化模式匹配功能的結構,使用Guard能夠在一個模式上作一些簡單的變量測試和比較。

4.6.2. 示例:

max(X, Y) -> when X > Y -> X;

max(X, Y) -> Y.

4.6.3. Guard組合關係

l  Guard1;Guard2...;Guardn 條件式中每一個條件式是or關係。

l  Guard1,Guard2...,Guardn 條件式中每一個條件式是and關係。

4.6.4. 合法的Guard表達式:

l  原子true。

l  其它常量(字典或者列表中的條目或者綁定變量), 這些在斷言表達式中都會被求值爲false。

l  表下表一中的這些內建函數。

l  比較表達式,參見表二。

l  算數表達式。參見表三。

l  布爾表達式。

l  短路布爾表達式

 

 

 

 

 

 

 

 

表一:

 

表二:

 

表三:

 

 

4.6.5. Guard例子

f(X, Y) when is_integer(X), X > Y, Y < 6 ->...

4.6.6. true Guard的使用:

true Guard能夠在if表達式的末尾處理全部爲被匹配的Guard。

if

   Guard -> Expression1;

   Guard2 -> Expression2;

   …

   True -> Expressions

end

 

4.7.  記錄(Records)

4.7.  

4.7.1. 使用場景

當元組的元素數量比較大的時候咱們可能不知道某個【元素】的具體意義,這個時候就可使用記錄。

4.7.2. 申明示例:

-record(todo, {status=reminder,who=joe,text}).

4.7.3. 在shell中讀取recode的方法:

rr(SomeErlangHeadFile).

4.7.4. 使用示例:

1>#todo{}.

#todo{status = reminder, who=joe, text = undefined}

3>X1 = #todo{status = urgent, text = "Fix errata in book"}.

#todo{status = urgent, who = joe, text = "Fix errata in book"}

4>X2 = X1#todo{status = Done}

#todo{status = done, who = joe, text = "Fix errata in book"}

 

5>#todo{who = W, text, Txt} = X2.

#todo{status = done, who = joe, text = "Fix errata in book"}

6>W.

joe

7>X2#todo.text.

"Fix errata in book"

4.7.5. 在函數中對記錄進行模式匹配:

clear_status(#todo{status=S, who=W}) ->

R#todo{status=finished}

4.7.6. 記錄只是元組的假裝

11>X2.

#todo{status = done, who = joe, text = "Fix errata in book"}

12>rf(todo).

Ok

13>X2.

{todo, done, joe, "Fix errata in book"}

4.8.  case和if表達式

4.8.1. case語句的語法

case Expression of

Pattern1 [when Guard1] -> Expr_seq1;、

Pattern2 [when Guard2] -> Expr_seq1;

...

End

4.8.2. case語句示例:

filter(P, [H|T]) ->

case P(H) of

true -> [H|filter(P, T)];

    false -> filter(P, T)

end;

filter(P, []) ->

  [].

 

4.8.3. if語句的語法

if

Guard1 ->

   Expr_seq1;

Guard ->

    Expr_seq1;

...

End

5. erlang中的異常

5.1.  erlang異常的產生

       異常常常在系統內部錯誤或在代碼中顯式調用throw(Exception), exit(Exception), erlang:error(Exception).

5.2.  本身生成異常的方法

l  exit(Why)

當想要終止當前進程的時候,就須要用到這個函數,若是這個異常未被捕獲,那麼系統會向全部與當前進程相鏈接的進程廣播{「EXIT」, Pid, Why}消息。

l  這個函數用於拋出一個調用者可能會捕獲的異常,在這種狀況下,有必要爲函數添加註釋說明它會拋出這個異常。這個函數的調用者有兩種選擇,要麼忽略這些異常,要麼將這個調用包含在try…catch表達式中並對錯誤進行處理。

l  erlang:error(Why)

這個函數用於拋出那些」崩潰錯誤」。這些異常應該是那些調用者不會真正意識到去處理的致命錯誤,能夠將它等同於內部產生的系統錯誤。

5.3.  try…catch

5.3.1. 語法形式:

try FuncOrExpressionSequence of

Pattern1 [when Guard1] -> Expressions1;

 Pattern2 [when Guard2] -> Expressions2;

 ...

catch

 ExceptionType: ExPattern1 [when ExGuard1] ->ExExpressions1;

 ExceptionType: ExPattern2 [when ExGuard2] ->ExExpressions2;

 ...

after  %%after部分能夠省略

 AfterExpressions  %%這個地方的返回值將會被忽略

end

在以上語法中ExceptionType是throw, exit, error中的一種假如ExceptionType被忽略則它的默認類型爲throw.

 

5.3.2. 捕獲全部的錯誤

   try Expr

catch

    _:_ -> ...Code to handle all exceptions.

End

5.3.3. 使用示例:

 

(ej@tcim.com)1> c(try_test).

{ok,try_test}

(ej@tcim.com)2> try_test:demo1().

[{1,normal,a},

 {2,caught,thrown,a},

 {3,caught,exited,a},

 {4,normal,{'EXIT',a}},

 {5,caught,error,a}]

(ej@tcim.com)3> try_test:demo2().

[{1,a},

 {2,a},

 {3,{'EXIT',a}},

 {4,{'EXIT',a}},

 {5,

  {'EXIT',{a,[{try_test,generate_exception,1},

              {try_test,'-demo2/0-lc$^0/1-0-',1},

              {try_test,'-demo2/0-lc$^0/1-0-',1},

              {erl_eval,do_apply,5},

              {shell,exprs,7},

              {shell,eval_exprs,7},

              {shell,eval_loop,3}]}}}](ej@tcim.com)

 

6. Erlang高級語法

6.1.  二進制數據操做:

   示例一:

1> Bin1 = <<1,2,3>>.

<<1,2,3>>

2> Bin2 = <<4,5>>.

<<4,5>>

3> Bin3 = <<6>>.

<<6>>

4> list_to_binary([Bin1, 1, [2,3,Bin2],4|Bin3]).

<<1,2,3,1,2,3,4,5,4,6>>

 

示例二:

1> Red = 2.

2

2> Green = 61.

61

3>  Blue = 20.

20

4>  Mem = <<Red:5, Green:6, Blue:5>>.

<<23,180>>

5> <<R:5, G:6, B:5>> = Mem.

<<23,180>>

6> R.

2

6.2.  apply關鍵字

6.2.1. 格式

apply(Mod, Func, [Agr1, arg2,...,ArgN])

此方法調用模塊Mod中的參數爲[Agr1, arg2,...,ArgN]的Func方法。

6.2.2. 建議

若是可能的話應避免用此種方法調用其它模塊中的方法,當一個函數的參數個數提早知道,更好的調用方式是:M:F(Arg1, Arg2,....ArgN).

6.2.3. 使用示例:

1> apply(erlang, atom_to_list, [hello]).

"hello"

2> erlang:atom_to_list(hello).

"hello"

6.3.  (模塊)屬性

6.3.1. 常見模塊屬性

-module(modname).

-import(...).

-export(...).

-compile(Options).

-vsn(Version).

最後一個選項爲增長編譯選項,Options能夠是單個選項或者選項列表。

-compile(export_all)屬性常常被使用在調試程序中。

-vsn(Version).中的Version能夠是任意字符條目。

6.3.2. 自定義屬性

格式:

  -SomeTag(Value).

(例如:-purpose("example of attributes")

6.3.3. 常看模塊屬性

Module:module_info().

Module:module_info(exports).

6.4.  塊表達式(Block Expressions)

6.4.1. 語法形式

begin

Expr1,

...

ExprN

end

            塊表達式用來把一串表達式組織成一個相似子句的實體,塊表達式的值爲最後一個表達式的返回值。

6.5.  布爾類型

Erlang中沒有獨立的布爾類型,原子true和false取而代之被賦予了特殊的布爾語義,它們一般做爲布爾符號使用。

6.6.  布爾表達式

6.6.1. 4種布爾表達式:

not B1: 邏輯非

B1 and B2: 邏輯與

B1 or B2:  邏輯或

B1 xor B2: 邏輯異或

6.6.2. 使用舉例

1>not true.

false

2>true and false.

false

3>true or false.

true

 

6.7.  轉義符

6.7.1. 轉義列表

 

6.7.2. 使用舉例

1>  io:format("~w~n ", ["\b\d\e\f\n\r\s\t\v "]).

[8,127,27,12,10,13,32,9,11,32]

6.7.3. 表達式和表達式序列

在erlang中,任何能夠被求出值的東西都被稱做表達式。這意味着catch, if,try…catch等都是表達式,而相似記錄和模塊屬性等,這些不能被求值的都不是表達式。

 表達式序列是一系列由逗號分開的表達式。這些表達式都應該緊接放置於->以後,表達式序列E1,E2,…,En的值被定義爲序列中最後一個表達式的值。

6.8.  包含文件

-include(Filename)

Filename應該包好一個絕對或相對路徑以便預處理器可以定位到相應的文件。

-include_lib(Filename)

這是包含了erlang庫中的頭文件。

6.9.  列表操做符++和—

1> [1,2,3]++[4,5].

[1,2,3,4,5]

2> [a,b,c,1,d,e,1,x,y,1]--[1].

[a,b,c,d,e,1,x,y,1]

4> [a,b,c,1,d,e,1,x,y,1]--[1,1].

[a,b,c,d,e,x,y,1]

6.10.     宏

6.10.1.    語法

-define(Constant, Replacement).

-define(Func(Var1, Var2,...,Var), Replacement).

              使用

               -define(macro1(X, Y), {a, X, Y}).

                …

foo(A)

?macro1(A+10, b)

6.10.2.    預約義宏

?FILE 展開後爲目前文件名

?MODULE 展開後爲目前模塊名

?LINE 展開後爲目前行號

6.10.3.    宏的流程控制

-undef(Macro) .取消改宏定義,在這個語句以後不能調用這個宏。

-ifdef(Macro).只有Macro被定義後,纔對該行如下的代碼進行運算。

-ifndef(Macro).只有在不定義Macro的狀況下,纔對該行如下的代碼進行運算。

-else. 只能在-ifdef或-ifndef以後出現,若是條件爲false, 那麼改語句後的代碼才被執行。

-endif.標記-ifdef或-ifndef語句的結束。

6.10.4.    使用舉例

    -undefine(Macro).

    -ifdef(Macro).

    -ifndef(Macro).

    -else.

-endif.

 

 

-module(m1).  %%module name is m1

-export([start/0]).

 

-ifdef(debug).

-define(TRACE(X), io:format("TRACE ~p:~p ~p~n",[?MODULE, ?LINE, X])).

-else.

-define(TRACE(X), void).

-endif.

 

start() ->  loop(5).

 

loop(0) ->

    void;

loop(N) ->

    ?TRACE(N),

    loop(N-1).

 

編譯以上腳本的方法:c(m1,{d, debug}).

運行方法:m1:start().

 

6.11.     在模式中使用匹配操做符

在函數參數中將傳進來的參數在參數列表中儘可能賦給一個臨時變量, 這樣在接下來的操做中會比較方便,如:

func1([{tag1, A, B}=Z|T])

    

6.12.     數值類型

6.12.1.    整數

l  傳統語法 直接書寫10, 50, -7。

l  K進制整數 語法K#Digits來表示

1> 7#456114.

81351

l  $語法 語法$C表示ASCII字符C的整數值。

6.12.2.    浮點數

1.0   3.14 -2.3E+6  23.56e-27

浮點數的範圍:-10^323~10^308

6.13.     操做符優先級

 

6.14.     進程字典

Erlang的每一個進程都有本身的私有數據存儲,叫作進程字典。進程字典是由一系列組成的關聯數組,進程字典的操做方法以下:

l  @spec put(Key, Value) -> OldValue

增長一個鍵值到進程字典,若是進程字典中原來就有這個鍵,那麼這個值將會被返回,若是進程字典中原來沒有這個鍵,那麼將會返回atom類型的undefined。

l  @spec get(Key) ->Value

l  @spec get() -> [{Key, Value}...]

l  @spec get_keys(Value) ->[Key].

l  @spec erase(Key) ->Value.

l  @spec erase() ->[{Key, Value}].  --擦除進程字典中的全部鍵值

6.15.     引用

引用是全局惟一的erlang值,使用BIF erlang:make_ref()來建立引用,引用適用於建立那些惟一標籤的場合,例如:在一個BUG跟蹤系統中,能夠給每個新的bug報告加入一個引用,以便改記錄賦予一個惟一標識。

6.16.     短路布爾表達式

Expr1 orelse Expr2

首先求值的是表達式Expr1。若是Expr1爲true,那麼Expr2就不會被求值,若是Expr1運算結果爲false,纔會對Expr2進行求值。

6.17.     比較表達式

6.17.1.    爲了進行比較,erlang按照下面的方式爲全部類型定義了大小比較順序

number < atom < reference < fun < port < pid < tuple < list < binary.

             

6.17.2.    比較表達式

 

除了=:=和=/=, 全部的條目比較運算符在比較數字的時候有以下規則:

l  在比較的過程當中若是有一個數字爲整數另外一個爲浮點數則在比較前整數會轉變爲浮點數。

l  若是都是整數或者浮點數則沒有數據轉換。

示例:

1>15 =:= 15.0 數據類型不轉的狀況

False

2>15 == 15.0  數據類型轉的狀況

True

6.18.     Underscore Variables(強調變量,下劃線變量)

正常狀況下,假如一個變量在一個子句(clause)中僅被使用了一次,編譯器將會生成一個警告, 由於這常常被認爲是一種錯誤的標誌,若是在一個變量前加一個下劃線將不會生成這樣一個警告。

 

7. 編譯和運行erlang程序

7.1.  和運行環境相關的API

如下函數設置erlang程序運行時模塊的搜索路徑:

@spec code:get_path()

@spec code:add_patha(Dir) => true|{error, bad_directory}  %%在模塊搜索目錄頭上增長搜索目錄

@spec code:add_pathz(Dir) => true|{error, bad_directory}  %%在模塊搜索目錄尾上增長搜索目錄

@spec code:all_loaded()

獲取erlang程序運行的起始目錄:

init:get_argument(home).

 

8. 並行編程

8.1.  Erlang中進程特色

l  建立和摧毀進程的速度很快。(2-4ms(微妙),win7 32 bit 操做系統,雙核CPU,3.37G內存)

l  進程的行爲在全部的操做系統中表現的同樣。

l  咱們能夠有大量的進程。

l  進程之間沒有內存共享,它們是徹底獨立的。

l  進程之間交互的惟一方式是消息傳遞。

8.2.  Erlang進程的理解:

 

(ej@tcim.com)1> c(processes).

{ok,processes}

(ej@tcim.com)2> processes:max(20000).

Maximum allowed processes:32768

Process spawn time=3.1 (3.15) microseconds

ok

修改默認最大進程數的方法:

erl +P 100000  將系統的最大線程數設置爲10萬。

8.3.  併發原語

l  Pid = spawn(Fun)

創建一個新進程 此進程和調用進程並行工做。

l  Pid|Message (Pid1 | Pid2 |...|M)

"|"表明發送操做,消息發送是異步的。(在實際代碼中|是!)

8.4.  設置接收超時值

8.4.1. 語法:

receive

    Pattern1 [when Guard1] ->

      Expressions1;

    Pattern2 [when Guard2] ->

      Expressions2;

    ...

   after Time ->  %%Time爲milliseconds毫秒

      Expressions

 end

 after部分只有在消息隊列中的全部消息被遍歷過以後纔會被執行.

 after section is checked only after pattern matching has been performed on all entries in mailbox.

8.4.2. receive的工做方式

l  當進入一個receive語句時,啓動一個計時器(只有在表達式有after部分才計時)。

l  從mailbox(郵箱)中取出第一個消息,而後嘗試對Pattern1,Pattern2等進行模式匹配。若是匹配成功,消息就從郵箱中刪除,對應的模式以後的表達式就會被求值。

l  若是郵箱中的第一個消息不能匹配receive語句的任何一個模式,那麼就會將第一個消息從郵箱中刪除並送入一個「保存隊列中」,而後繼續嘗試郵箱中的第二個消息。這個過程會不斷的重複直到找到匹配的消息或者郵箱中全部的消息所有被檢查了。

l  若是郵箱中全部的消息都不能匹配,那麼就掛起進程,直到下一次又有新的消息進入郵箱時在對該進程進行從新調度執行。注意,當一個新消息到達時,只對新消息進行匹配而不會對保存隊列中的消息進行再次匹配

l  一個消息若是被匹配,那麼存入保存隊列中的全部消息就會按照它們到達進程的時間前後順序從新放回到郵箱中,這時,若是開啓了一個計時器,那麼計時器將會被清空。

l  若是在咱們等待一個消息時觸發了計時器,那麼先對超時部分中的語句進行求值而後把存入保存隊列中的全部消息按照它們達到進程的時間前後順序從新放回到郵箱中。

8.4.3. 超時使用示例:

 

1>  c(stimer).

ok

2>  Pid = stimer:start(5000, fun() -> io:format("time event~n") end).

<0.146.0>

time event

3>  Pid1 = stimer:start(25000, fun() -> io:format("timer event~n") end).

<0.143.0>

4>  stimer:cancel(Pid1).

cancel

 

8.5.  註冊進程

erlang進程可以發佈一個進程的ID以致於任何在系統中的進程能夠和他交互。有如下4個方法能夠操做註冊進程:

l  spec register(AnAtom, Pid)

註冊一個名字叫作AnAtom,ID是Pid的進程,假如AnAtom已經被註冊過了,那麼這個註冊操做將會失敗。

l  spec unregister(AnAtom)

移除一個與AnAtom有關的註冊。

假如一個進程死掉,它將會自動的取消註冊。

l  spec whereis(AnAtom) -> Pid | Undefined

l  registered() -> [AnAtom::atom()]

返回在系統中註冊的全部的進程的列表。

8.6.  從另外一個模塊中啓動進程的方法

spawn(Mod, FuncName, args)

 

9. 並行編程中的錯誤處理

9.1.  錯誤處理的細節

9.1.1. 錯誤處理中的3種基礎概念

l  鏈接(Links): 一個鏈接定義了一個錯誤傳播路徑,假如兩個進程鏈接到一塊兒而後其中的一個死掉,接下來一個退出信號將會被髮送到另外一個進程,鏈接到一個進程的其它進程被叫作這個進程的進程集合。

l  退出信號(Exit Signals):一個進程死掉的消息會發送給這個進程的進程集合。進程能夠調用exit(Reason)或者程序內部發生錯誤將會發送進程退出的消息。除此以外Pid1還能夠調用exit(Pid2, X)發送{"EXIT", Pid, X}消息給Pid2, 可是Pid1不會死掉。

l  系統進程(system processes): 能夠將其它進程的退出消息轉化爲普通的消息的進程叫作系統進程。通常進程能夠調用內建函數process_flag(trap_exit, true)來將本身轉化爲系統進程。

9.2.  錯誤處理原語(Error Handing Primitive)

l  @spec spawn_link(Fun) ->Pid

spawn_link是原子操做,其不等於spawn以後調用link,由於調用spawn以後的進程可能死掉。

l  @spec process_flag(trap_exit, true)

將目前的進程轉化爲系統進程。

也能夠用process_flag(trap_exit, false) 將系統進程轉化爲通常進程。

l  @spec link(Pid) ->true

假如鏈接一個不存在的進程,則noproc異常拋出。

l  @spec unlink(Pid) ->true

解鏈接。

l  @spec exit(Why) -> none()

這條原語引發目前進程由於Why緣由結束。

l  @spec exit(Pid, Why) -> true

此條原語發送緣由爲Why的退出信號。

l  @spec erlang:monitor(process, item) -> MonitorRef

此條原語安裝了一個監督者,item是PID或者一個進程的註冊名。

  1. 10.    分佈式編程

10.1.     名字服務服務器

參見中文<<erlang程序設計>> p145。

10.2.     分佈式原語

erlang分佈式的中心概念是節點,一個節點。相互交流的節點之間cookie要相同。erlang:set_cookie() 可設置節點的cookie值。

l  @spec spawn(Node, Fun) ->Pid

約等於spawn(Fun)

在一個節點上產生一個進程

l  @spec spawn(Node, Mod, Func, ArgList) -> Pid

約等於spawn(Mod, Func, Arglist)。

這個方法是原子操做執行過程當中不能被打斷。

l  @spec spawn_link(Node, Fun) ->Pid

相似:spawn_link(Fun)。

l  @spec spawn_link(Node, Mod, Func, ArgList) -> Pid

相似於:spawn(Node, Mod, Func, ArgList)。

新建立的進程連接到目前的進程。

l  @spec disconnect_node(Node) -> bool |ignored

強制中斷一個節點。

l  @spec monitor_node(Node, Flag) -> true

假如Flag=true,監視被打開,Flag = false, 監視被關閉。

當flag = true時調用此內建函數的進程將會收到{nodeup, Node},

當某個節點不在此進程的監視集合中的時候{nodedown, Node}將會被收到。

l  @spec node() -> Node

此方法返回本地節點的名字,

l  @spec node(Arg) -> Node

此函數返回Arg所在的節點,Arg能夠是PID, 一個名字引用,或者一個port。

l  @spec nodes() -> [Node]

返回一個鏈接上的全部節點的列表。

l  @spec is_alive() ->bool()

 

  1. 11.    接口技術

接口技術就是讓erlang與其餘語言結合,erlang與其它語言結合的方式也是發送消息機制。

   

  1. 12.    gen_server

12.1.     簡介

gen_server實現了一個client_server模式,在這個模式中的client能夠有任意個。這種模式一般被使用在不一樣的客戶端想要共享共同的資源,此中狀況下服務端負責管理這些共享的資源。

12.2.     代碼

 

12.3.     使用方法

(ej@tcim.com)1> c(my_bank).

{ok,my_bank}

(ej@tcim.com)2> my_bank:start().

{ok,<0.79.0>}

(ej@tcim.com)3> my_bank:new_account("joe").

{welcome,"joe"}

(ej@tcim.com)4> my_bank:deposit("joe", 20).

{thanks,"joe",your_balance_is,20}

(ej@tcim.com)5> my_bank:deposit("joe", 50).

{thanks,"joe",your_balance_is,70}

(ej@tcim.com)6> my_bank:withdraw("joe", 15).

{thanks,"joe",your_balance_is,55}

(ej@tcim.com)7> my_bank:withdraw("joe", 30).

{thanks,"joe",your_balance_is,25}

(ej@tcim.com)8> my_bank:stop().

stopped

  

12.4.     my_bank.erl文件代碼分析

12.4.1.    –behaviour(gen_server).(11行)此句的做用是當咱們忘記須要實現的回調函數的時候編譯器會產生警告或者錯誤消息。

12.4.2.    start().(19行)此句爲啓動一個本地(回調)服務,將第一個列表參數中的local換爲global參數,將啓動一個能在由erlang節點組成的集羣中全局訪問的(回調)服務。此函數通過gen_server中的事件分發最終會調用my_bank.erl模塊中的init([])(28行)函數。

12.4.3.    stop().(20行)此句爲中止本地回調服務。此函數通過gen_server中的事件分發最終會調用my_bank.erl模塊中的handle_call(stop, _From, Tab)(57行)函數。

12.4.4.    new_account(…), deposit(…), withdraw(…)爲在開戶,存款,取款功能。此函數最終會調用my_bank.erl模塊中的handle_call(…)函數。

12.4.5.    handle_cast(…)(60行)是gen_server:cast(…)的回調。cast函數是一種沒有返回值的調用。(返回的時候的atom:noreply).

12.4.6.    Handle_info(…)用來處理髮送給服務器的原生消息。原生消息就是:若是服務器和其餘的進程創建了鏈接,而且正在捕捉退出事件,那麼它有可能會忽然收到意外的{‘EXIT’, Pid, What}這樣的消息。又或者,系統中的其它進程得到了服務器程序的PID,那麼它可能會給服務器發送消息。

12.4.7.    terminate(…).服務器終止的時候調用的回調函數。

12.4.8.    code_change(…).在熱代碼升級的時候被回調。

 

  1. gen_event

13.1.     簡介

一個事件處理器就是一個命名對象(一個命名進程),這個命名對象能夠接收相應的事件而且處理,在下面的代碼中event_handler.erl就至關於gen_event.erl.

13.2.     代碼

 

13.3.     使用方法

(ej@tcim.com)1>event_handler:make(errors).

true

(ej@tcim.com)2> event_handler:event(errors, hi).

{event,hi}

fun ret is:void

(ej@tcim.com)3>motor_controller:add_event_handler().

{add,#Fun<motor_controller.0.130547767>}

(ej@tcim.com)4>event_handler:event(errors, hi).

motor_controller ignored event: hi

{event,hi}

fun ret is:void

13.4.     event_handler.erl和motor_control.erl代碼分析

l  event_handler.erl分析

  • make函數(14行)註冊一個名稱爲Name的進程,進程中執行的函數爲my_handler(…).
  • add_handler(…)(17行)改變my_handler函數中的參數(函數指針)。
  • event(…)(20行)向Name進程發送消息。

            

l  motor_controller.erl分析

  • add_event_handler(…)調用event_handler.erl中的add_handler函數。
  • controller(…)爲add_event_handler傳遞給add_handler的」函數指針」。

 

  1. gen_fsm

14.1.     簡介

有限狀態機能夠被描述爲如下的關係:

State(S) x Event(E)  ->  Action(A), State(S’)

假如咱們在狀態S,此時發生了一個E事件,接下來應該執行動做A,而後改變狀態機的狀態至S’.

14.2.     代碼

 

14.3.     使用方法、

1> c(code_lock).

{ok,code_lock}

2> code_lock:start([1,2,3]).

{ok,<0.36.0>}

3> code_lock:button(1).

Now the code you input is: [1]

  • ok

4> code_lock:button(2).

Now the code you input is: [1,2]

  • ok

5> code_lock:button(3).

Now the code you input is: [1,2,3]

  • ok 

6> code_lock:button(1).

Now the code you input is: [1]

  • ok

7> code_lock:button(2).

Now the code you input is: [1,2]

  • ok

8> code_lock:button(2).

Now the code you input is: [1,2,2]

  • ok

Wrong Start

14.4.     code_lock.erl文件解釋

參見代碼註釋。

  1. 監督樹

15.1.     簡介

監督樹是監督一個或者多個其它進程的進程,監督進程通常負責啓動掛掉的進程。在啓動子進程的時候能夠設置重啓被監督進程的策略..

15.2.     代碼

     

 

 

15.3.     使用方法

因爲指令比較多這裏只列出指令:

l  erl -boot start_sasl -config elog2.config(啓動erlang)

l  sellaprime_supervisor:start_in_shell_for_testing().

l  area_server:area({square,10}).

l  area_server:area({rectange,10, 20}).

l  area_server:area({square, 25}).

l  prime_server:new_prime(20).

說明:

start_sasl啓動標誌創建一個適合運行產品級的的系統,(System Architecture Support Library, SASL)將會關注於錯誤日誌,過載保護等等。

注意修改elog2.config中的日誌文件路徑。

15.4.     sellaprime_supervisor.erl文件解釋

15.4.1.    start_in_shell_for_testing(…)開啓一個監督進程,而且將調用進程與此監督進程分離。

15.4.2.    init([]).(27行)啓動兩個子監督進程。關於開啓子進程中進程列表中每一項的意義參見:erlang程序設計中文版P298, 英文版P353。

 

  1. 熱代碼切換

16.1.     代碼

 

 

16.2.     使用方法

(ej@tcim.com)1> server3:start(name_server, name_server1).

true

(ej@tcim.com)2> name_server1:add(joe, "at home").

  • ok

(ej@tcim.com)3> name_server1:add(helen, "at work").

  • ok

(ej@tcim.com)4> server3:swap_code(name_server, new_name_server).

ack

(ej@tcim.com)5> new_name_server:all_names().

[joe,helen]

16.3.     文件解釋

略。

 

  1. 完整的OTP應用程序

17.1.     代碼

在上一節監督樹的那幾個文件的基礎上在加上如下文件:

 

17.2.     使用方法

切換測試文件所在路徑執行命令:erl -boot start_sasl -config elog2.config,而後執行一下erlang指令:

1> application:loaded_applications().

[{kernel,"ERTS  CXC 138 10","2.13.5"},

 {sasl,"SASL  CXC 138 11","2.1.9"},

 {stdlib,"ERTS  CXC 138 10","1.16.5"}]

2> application:load(sellaprime).

  • ok

3> application:loaded_applications().

[{kernel,"ERTS  CXC 138 10","2.13.5"},

 {sasl,"SASL  CXC 138 11","2.1.9"},

 {stdlib,"ERTS  CXC 138 10","1.16.5"},

 {sellaprime,"The Prime Number Shop","1.0"}]

4> application:start(sellaprime).

*** my_alarm_handler init:{xyz,{alarm_handler,[]}}

area_server starting

prime_server start_link

prime_server starting

  • ok

5> application:stop(sellaprime).

prime_server stopping

area_server stopping

 

=INFO REPORT==== 1-Feb-2012::10:21:50 ===

    application: sellaprime

    exited: stopped

    type: temporary

  • ok

6> application:loaded_applications().

[{kernel,"ERTS  CXC 138 10","2.13.5"},

 {sasl,"SASL  CXC 138 11","2.1.9"},

 {stdlib,"ERTS  CXC 138 10","1.16.5"},

 {sellaprime,"The Prime Number Shop","1.0"}]

7> application:unload(sellaprime).

  • ok

8> application:loaded_applications().

[{kernel,"ERTS  CXC 138 10","2.13.5"},

 {sasl,"SASL  CXC 138 11","2.1.9"},

 {stdlib,"ERTS  CXC 138 10","1.16.5"}]

             說明: 第一條指令檢查erlang運行系統中正在運行的應用程序。

                   第二條指令加載了應用程序,加載動做會載入全部的代碼,但不會啓動應用程序。

                   第四條指令啓動了應用程序。

                   第五條指令將這個應用程序中止。

                   第七條指令卸載sellaprime應用程序。

17.3.     Sellaprime.app文件解釋

此文件包含了應用程序的說明,已經此應用程序要加載的模塊等應用程序加載相關的信息。

相關文章
相關標籤/搜索