• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            教父的告白
            一切都是紙老虎
            posts - 82,  comments - 7,  trackbacks - 0
              任何一門語言都有自己的錯誤處理機制,Erlang也不例外,語法錯誤編譯器可以幫你指出,而邏輯錯誤和運行時錯誤就只有靠程序員利用Erlang提供的機制來妥善處理,放置程序的崩潰。
                Erlang的機制有:
            1)監控某個表達式的執行
            2)監控其他進程的行為
            3)捕捉未定義函數執行錯誤等

            一、catch和throw語句
                調用某個會產生錯誤的表達式會導致調用進程的非正常退出,比如錯誤的模式匹配(2=3),這種情況下可以用catch語句:
                                                  catch expression
                試看一個例子,一個函數foo:

            java 代碼
             
            1. foo(1) ->  
            2. hello;  
            3. foo(2) ->  
            4. throw({myerror, abc});  
            5. foo(3) ->  
            6. tuple_to_list(a);  
            7. foo(4) ->  
            8. exit({myExit, 222}).  

            當沒有使用catch的時候,假設有一個標識符為Pid的進程調用函數foo(在一個模塊中),那么:
            foo(1) - 返回hello
            foo(2) - 語句throw({myerror, abc})執行,因為我們沒有在一個catch中調用foo(2),因此進程Pid將因為錯誤而終止。

            foo(3) - tuple_to_list將一個元組轉化為列表,因為a不是元組,因此進程Pid同樣因為錯誤而終止

            foo(4) - 因為沒有使用catch,因此foo(4)調用了exit函數將使進程Pid終止,{myExit, 222} 參數用于說明退出的原因。

            foo(5) - 進程Pid將因為foo(5)的調用而終止,因為沒有和foo(5)匹配的函數foo/1。

                讓我們看看用catch之后是什么樣:
            java 代碼
             
            1. demo(X) ->  
            2. case catch foo(X) of  
            3.   {myerror, Args} ->  
            4.        {user_error, Args};  
            5.   {'EXIT', What} ->  
            6.        {caught_error, What};  
            7.   Other ->  
            8.        Other  
            9. end.  

            再看看結果,
            demo(1) - 沒有錯誤發生,因此catch語句將返回表達式結果hello
            demo(2) - foo(2)拋出錯誤{myerror, abc},被catch返回,因此將返回{user_error,abc}

            demo(3) - foo(3)執行失敗,因為參數錯誤,因此catch返回{'EXIT',badarg'},最后返回{caught_error,badarg}

            demo(4) - 返回{caught_error,{myexit,222}}
            demo(5) - 返回{caught_error,function_clause}

                使用catch和throw可以將可能產生錯誤的代碼包裝起來,throw可以用于尾遞歸的退出等等。Erlang是和scheme一樣進行尾遞歸優化的,它們都沒有顯式的迭代結構(比如for循環)

            二、進程的終止
                在進程中調用exit的BIFs就可以顯式地終止進程,exit(normal)表示正常終止,exit(Reason)通過Reason給出非正常終止的原因。進程的終止也完全有可能是因為運行時錯誤引起的。

            三、連接的進程
                進程之間的連接是雙向的,也就是說進程A打開一個連接到B,也意味著有一個從B到A的連接。當進程終止的時候,有一個EXIT信號將發給所有與它連接的進程。信號的格式如下:
                           {'EXIT', Exiting_Process_Id, Reason}
            Exiting_Process_Id 是指終止的進程標記符
            Reason 是進程終止的原因。如果Reason是normal,接受這個信號的進程的默認行為是忽略這個信號。默認對Exit信號的處理可以被重寫,以允許進程對Exit信號的接受做出不同的反應。
            1.連接進程:
            通過link(Pid),就可以在調用進程與進程Pid之間建立連接
            2.取消連接
            反之通過unlink(Pid)取消連接。
            3.創立進程并連接:
            通過spawn_link(Module, Function, ArgumentList)創建進程并連接,該方法返回新創建的進程Pid

                通過進程的相互連接,許多的進程可以組織成一個網狀結構,EXIT信號(非normal)從某個進程發出(該進程終止),所有與它相連的進程以及與這些進 程相連的其他進程,都將收到這個信號并終止,除非它們實現了自定義的EXIT信號處理方法。一個進程鏈狀結構的例子:
            java 代碼
             
            1. -module(normal).  
            2. -export([start/1, p1/1, test/1]).  
            3. start(N) ->  
            4. register(start, spawn_link(normal, p1, [N - 1])).  
            5.  p1(0) ->  
            6.    top1();  
            7.  p1(N) ->  
            8.    top(spawn_link(normal, p1, [N - 1]),N).  
            9. top(Next, N) ->  
            10. receive  
            11. X ->  
            12. Next ! X,  
            13. io:format("Process ~w received ~w~n", [N,X]),  
            14. top(Next,N)  
            15. end.  
            16. top1() ->  
            17. receive  
            18. stop ->  
            19. io:format("Last process now exiting ~n", []),  
            20. exit(finished);  
            21. X ->  
            22. io:format("Last process received ~w~n", [X]),  
            23. top1()  
            24. end.  
            25. test(Mess) ->  
            26. start ! Mess.  

            執行:
            java 代碼
             
            1. > normal:start(3).  
            2. true  
            3. > normal:test(123).  
            4. Process 2 received 123  
            5. Process 1 received 123  
            6. Last process received 123  
            7.   
            8. > normal:test(stop).  
            9. Process 2 received stop  
            10. Process 1 received stop  
            11. Last process now exiting  
            12. stop  

            四、運行時失敗
                一個運行時錯誤將導致進程的非正常終止,伴隨著非正常終止EXIT信號將發出給所有連接的進程,EXIT信號中有Reason并且Reason中包含一個atom類型用于說明錯誤的原因,常見的原因如下:

            badmatch - 匹配失敗,比如一個進程進行1=3的匹配,這個進程將終止,并發出{'EXIT', From, badmatch}信號給連接的進程

            badarg  - 顧名思義,參數錯誤,比如atom_to_list(123),數字不是atom,因此將發出{'EXIT', From, badarg}信號給連接進程

            case_clause - 缺少分支匹配,比如
               
            java 代碼
             
            1. M = 3,  
            2. case M of  
            3.   1 ->  
            4.     yes;  
            5.   2 ->  
            6.     no  
            7. end.  

            沒有分支3,因此將發出{'EXIT', From, case_clause}給連接進程

            if_clause - 同理,if語句缺少匹配分支

            function_clause - 缺少匹配的函數,比如:
            java 代碼
             
            1. foo(1) ->  
            2.   yes;  
            3. foo(2) ->  
            4.   no.  

            如果我們調用foo(3),因為沒有匹配的函數,將發出{'EXIT', From, function_clause} 給連接的進程。

            undef - 進程執行一個不存在的函數

            badarith - 非法的算術運算,比如1+foo。

            timeout_value - 非法的超時時間設置,必須是整數或者infinity

            nocatch - 使用了throw,沒有相應的catch去通訊。

            五、修改默認的信號接收action
               當進程接收到EXIT信號,你可以通過process_flag/2方法來修改默認的接收行為。執行process_flag(trap_exit, true)設置捕獲EXIT信號為真來改變默認行為,也就是將EXIT信號作為一般的進程間通信的信號進行接受并處理;process_flag (trap_exit,false)將重新開啟默認行為。
               例子:
            java 代碼
             
            1. -module(link_demo).  
            2. -export([start/0, demo/0, demonstrate_normal/0, demonstrate_exit/1,  
            3. demonstrate_error/0, demonstrate_message/1]).  
            4. start() ->  
            5.   register(demo, spawn(link_demo, demo, [])).  
            6. demo() ->  
            7.   process_flag(trap_exit, true),  
            8. demo1().  
            9.   demo1() ->  
            10.   receive  
            11.     {'EXIT', From, normal} ->  
            12.       io:format("Demo process received normal exit from ~w~n",[From]),  
            13.      demo1();  
            14.     {'EXIT', From, Reason} ->  
            15.       io:format("Demo process received exit signal ~w from ~w~n",[Reason, From]),  
            16.      demo1();  
            17.     finished_demo ->  
            18.       io:format("Demo finished ~n", []);  
            19.     Other ->  
            20.       io:format("Demo process message ~w~n", [Other]),  
            21.      demo1()  
            22.   end.  
            23. demonstrate_normal() ->  
            24.   link(whereis(demo)).  
            25. demonstrate_exit(What) ->  
            26.   link(whereis(demo)),  
            27.   exit(What).  
            28. demonstrate_message(What) ->  
            29.   demo ! What.  
            30. demonstrate_error() ->  
            31.   link(whereis(demo)),  
            32.   1 = 2.  
            33.    

                創建的進程執行demo方法,demo方法中設置了trap_exit為true,因此,在receive中可以像對待一般的信息一樣處理EXIT信號,這個程序是很簡單了,測試看看:
            java 代碼
             
            1. > link_demo:start().  
            2. true  
            3. > link_demo:demonstrate_normal().  
            4. true  
            5. Demo process received normal exit from <0.13.1>  
            6. > link_demo:demonstrate_exit(hello).  
            7. Demo process received exit signal hello from <0.14.1>  
            8. ** exited: hello **  
            9.   
            10. > link_demo:demonstrate_exit(normal).  
            11. Demo process received normal exit from <0.13.1>  
            12. ** exited: normal **  
            13.   
            14. > link_demo:demonstrate_error().  
            15. !!! Error in process <0.17.1> in function  
            16. !!! link_demo:demonstrate_error()  
            17. !!! reason badmatch  
            18. ** exited: badmatch **  
            19. Demo process received exit signal badmatch from <0.17.1>  

            六、未定義函數和未注冊名字
            1.當調用一個未定義的函數時,Mod:Func(Arg0,...,ArgN),這個調用將被轉為:
            error_handler:undefined_function(Mod, Func, [Arg0,...,ArgN])
            其中的error_handler模塊是系統自帶的錯誤處理模塊

            2.當給一個未注冊的進程名發送消息時,調用將被轉為:
            error_handler:unregistered_name(Name,Pid,Message)

            3.如果不使用系統自帶的error_handler,可以通過process_flag(error_handler, MyMod) 設置自己的錯誤處理模塊。

            七、Catch Vs. Trapping Exits
            這兩者的區別在于應用場景不同,Trapping Exits應用于當接收到其他進程發送的EXIT信號時,而catch僅用于表達式的執行。

            第8章介紹了如何利用錯誤處理機制去構造一個健壯的系統,用了幾個例子,我將8.2節的例子完整寫了下,并添加客戶端進程用于測試:
            java 代碼
             
            1. -module(allocator).  
            2. -export([start/1,server/2,allocate/0,free/1,start_client/0,loop/0]).  
            3. start(Resources) ->  
            4.    Pid = spawn(allocator, server, [Resources,[]]),  
            5. register(resource_alloc, Pid).  
            6. %函數接口  
            7. allocate() ->  
            8.    request(alloc).  
            9. free(Resource) ->  
            10.   request({free,Resource}).  
            11. request(Request) ->  
            12.   resource_alloc ! {self(),Request},  
            13.   receive  
            14.     {resource_alloc, error} ->  
            15.       exit(bad_allocation); % exit added here  
            16.     {resource_alloc, Reply} ->  
            17.       Reply  
            18.  end.  
            19. % The server.  
            20. server(Free, Allocated) ->  
            21.  process_flag(trap_exit, true),  
            22.  receive  
            23.    {From,alloc} ->  
            24.          allocate(Free, Allocated, From);  
            25.    {From,{free,R}} ->  
            26.         free(Free, Allocated, From, R);  
            27.    {'EXIT', From, _ } ->  
            28.        check(Free, Allocated, From)  
            29.  end.  
            30. allocate([R|Free], Allocated, From) ->  
            31.    link(From),  
            32.    io:format("連接客戶端進程~w~n",[From]),  
            33.    From ! {resource_alloc,{yes,R}},  
            34.    server(Free, [{R,From}|Allocated]);  
            35. allocate([], Allocated, From) ->  
            36.    From ! {resource_alloc,no},  
            37.    server([], Allocated).  
            38. free(Free, Allocated, From, R) ->  
            39.   case lists:member({R,From}, Allocated) of  
            40.    true ->  
            41.               From ! {resource_alloc,ok},  
            42.               Allocated1 = lists:delete({R, From}, Allocated),  
            43.               case lists:keysearch(From,2,Allocated1) of  
            44.                      false->  
            45.                             unlink(From),  
            46.                         io:format("從進程~w斷開~n",[From]);  
            47.                      _->  
            48.                             true  
            49.               end,  
            50.              server([R|Free],Allocated1);  
            51.    false ->  
            52.            From ! {resource_alloc,error},  
            53.          server(Free, Allocated)  
            54.  end.  
            55.   
            56. check(Free, Allocated, From) ->  
            57.    case lists:keysearch(From, 2, Allocated) of  
            58.          false ->  
            59.            server(Free, Allocated);  
            60.         {value, {R, From}} ->  
            61.            check([R|Free],  
            62.            lists:delete({R, From}, Allocated), From)  
            63. end.  
            64. start_client()->  
            65.     Pid2=spawn(allocator,loop,[]),  
            66.     register(client, Pid2).  
            67. loop()->  
            68.     receive  
            69.         allocate->  
            70.             allocate(),  
            71.             loop();  
            72.         {free,Resource}->  
            73.             free(Resource),  
            74.             loop();  
            75.         stop->  
            76.             true;  
            77.         _->  
            78.             loop()  
            79.     end.  
            80.       

            回家了,有空再詳細說明下這個例子吧。執行:
            java 代碼
             
            1. 1> c(allocator).  
            2. {ok,allocator}  
            3. 2> allocator:start([1,2,3,4,5,6]).  
            4. true  
            5. 3> allocator:start_client().  
            6. true  
            7. 4> client!allocate  
            8. .  
            9. allocate連接客戶端進程<0.37.0>  
            10.   
            11. 5> client!allocate.  
            12. allocate連接客戶端進程<0.37.0>  
            13.   
            14. 6> client!allocate.  
            15. allocate連接客戶端進程<0.37.0>  
            16.   
            17. 7> allocator:allocate().  
            18. 連接客戶端進程<0.28.0>  
            19. {yes,4}  
            20. 8> client!{free,1}.  
            21. {free,1}  
            22. 9> client!{free,2}.  
            23. {free,2}  
            24. 10> client!allocate.  
            25. allocate連接客戶端進程<0.37.0>  
            26.   
            27. 11> client!allocate.  
            28. allocate連接客戶端進程<0.37.0>  
            29.   
            30. 12> client!stop.  
            31. stop  
            32. 13> allocator:allocate().  
            33. 連接客戶端進程<0.28.0>  
            34. {yes,3}  
            35. 14> allocator:allocate().  
            36. 連接客戶端進程<0.28.0>  
            37. {yes,2}  
            38. 15> allocator:allocate().  
            39. 連接客戶端進程<0.28.0>  
            40. {yes,1}  
            41. 16>  

            posted on 2009-09-11 10:13 暗夜教父 閱讀(323) 評論(0)  編輯 收藏 引用 所屬分類: erlang

            <2010年2月>
            31123456
            78910111213
            14151617181920
            21222324252627
            28123456
            78910111213

            常用鏈接

            留言簿(2)

            隨筆分類

            隨筆檔案

            文章分類

            文章檔案

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            91久久婷婷国产综合精品青草| 99麻豆久久久国产精品免费 | 国产精品女同久久久久电影院| 久久久精品人妻一区二区三区蜜桃 | 久久久久精品国产亚洲AV无码| 久久乐国产综合亚洲精品| 久久久久99精品成人片直播| 久久久国产精品福利免费 | 久久福利片| 久久综合给合久久国产免费| 久久久久久国产精品无码下载| 77777亚洲午夜久久多喷| 国产AV影片久久久久久| 精品国产青草久久久久福利| 久久国产精品一国产精品金尊 | 久久国产精品-国产精品| 久久丫精品国产亚洲av| 久久久久亚洲AV成人网人人网站| 国产精品欧美久久久天天影视| 久久人人爽人爽人人爽av| 久久99精品久久久久久动态图 | 狠狠色丁香久久婷婷综合图片| 青青草原综合久久大伊人导航| 久久精品视频网| 日产精品99久久久久久| 色婷婷噜噜久久国产精品12p | 色偷偷88欧美精品久久久| 久久91亚洲人成电影网站| 日日躁夜夜躁狠狠久久AV| 久久人人爽人人澡人人高潮AV | 色婷婷综合久久久久中文字幕| 久久精品国产亚洲网站| 久久99国产综合精品| 午夜人妻久久久久久久久| 国产精品一区二区久久国产| 久久精品免费一区二区| 欧美激情一区二区久久久| 99久久精品免费看国产一区二区三区| 性做久久久久久久久久久| 亚洲伊人久久成综合人影院 | 日韩欧美亚洲综合久久影院Ds |