• <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>
            Fork me on GitHub
            隨筆 - 215  文章 - 13  trackbacks - 0
            <2016年8月>
            31123456
            78910111213
            14151617181920
            21222324252627
            28293031123
            45678910


            專注即時通訊及網游服務端編程
            ------------------------------------
            Openresty 官方模塊
            Openresty 標準模塊(Opm)
            Openresty 三方模塊
            ------------------------------------
            本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            相冊

            Awesome

            Blog

            Book

            GitHub

            Link

            搜索

            •  

            積分與排名

            • 積分 - 215445
            • 排名 - 118

            最新評論

            閱讀排行榜

            本文為csdn I_myours 原創,此處為轉載。作者秉持了 free, open, share 的原則,但敬請各位在轉載的時候自覺標明原創作者及出處,這是各位對作者勞動成果的自覺尊重!
            作者:I_myours
            原文:http://blog.csdn.net/wwh578867817/article/details/49774169

            首先,我們聊聊現實世界中的并發。

            我曾經舉過一個并發和并行的例子:

            老媽在很短的時間給我安排了很多任務,吃包子,拖地,洗碗…等等 
            由于我母親大人比較嚴厲,所以我“愉快”地接受了所有任務。 
            這就是所謂的并發,在某一時段,能接受的事件 
            我只有兩只手,可以用一只手來吃包子,另一只手來拖地。 
            這就是所謂的并行,在某一時刻,能處理的事件

            現實世界中,并發的事情無處不在,就拿上面的例子來說,我答應了老媽的多個要求,老媽也收到了我的回復。這說明我們的大腦天生就是并發的,它可以在某一時段接受大量的信息。

            所以,符合我們思維的并發應該如上圖,我可以接收老媽的多個消息,即使老爸回來給我發消息,我也能接收。

            這是現實世界中的并發,人與人之間是單獨的個體,通過發送消息進行交流 
            此時,你可能已經猜到這就是Erlang 中的并發,Actor模型的樣子。 
            讓我們先跨過這個,來看看傳統的并發是如何做的。


            共享內存

            在我們平時寫的程序中,并發事件處理一般是通過多線程或多進程來處理。 
            某一時刻,我們同時接收到了多條請求,通常的做法是將它放入隊列(共用的內存)中去,每一個線程或者進程都會去隊列中取消息進行處理。 
            如下圖: 
            這里寫圖片描述

            此時,隊列中的內存是共享的,多個線程或進程存取會造成竟態條件,也就是產生競爭,發生錯誤。

            通常的做法是 加鎖

            線程或進程必須先搶到鎖,接著搶到鎖的才能訪問隊列中的消息。 
            注意,鎖是錯誤的源泉 
            我們應該都遇到過死鎖等錯誤,先不說性能,調試起來就很麻煩。

            那么 無鎖 CAS 呢?

            每個線程或進程都先取出一條消息,保存舊值,拷貝一份后修改為新值,將自己保存的舊值和原先隊列中的值比較,若相同說明沒有被其它線程或進程修改,則這條消息屬于該線程或進程,可以處理此消息。 
            若舊值和新值不同,說明有其它線程或進程得到了此消息,則循環進行下一次 CAS 操作。 
            這就是所謂的copy and set

            這里我們不對比這兩種方式以及一會說的 Actor 模型性能的好壞。 
            因為在不同的場景下,不同的方式性能也是不同的。我們需要根據具體情況,測試,分析,從而得出性能最優的方式。

            順便提一句,Actor只是模型,僅僅表現給我們的是消息傳遞。至于它內部怎樣實現這里不討論,感興趣可以看看內部實現

            不過從剛才的描述來看,上述方式都不符合我們的思維,而且略復雜,相信沒有人是通過 共享大腦 來傳遞及處理消息的吧?


            來看看 Actor 模型

            Actor 模型概念非常簡單,且非常符合我們的思維。 
            萬物皆為 Actor,Actor 與 Actor 之間通過發送消息來通信。

            就和人類一般,一個人是一個 Actor,人與人之間通過消息來交互。

            別驚訝,Actor 模型就是這么簡單。(Actor 模型更多細節參見 Wiki Actor)

            接著我們來看 Erlang 是如何運用 Actor 模型的。

            Erlang 的 Actor 模型也非常簡單。 
            在 Erlang 中,進程為最小的單位,也就是所謂的 Actor。注意 Erlang 的進程不是我們傳統上的進程,它運行在 Erlang 虛擬機上,非常小,非常輕,可以瞬間創建上萬,甚至幾十萬個,進程間完全是獨立的,不共享內存。在進程運行時若出現錯誤,由于進程的輕量級,Erlang 采取的措施是“讓其他進程修復”和“任其崩潰”。在 Erlang 上查看默認限制數量是26萬多,可以進行修改。每個進程創建后都會有一個獨一無二的 Pid,這些進程之間通過 Pid 來互相發送消息,進程的唯一交互方式也是消息傳遞,消息也許能被對方收到,也許不能,收到后可以處理該消息。如果想知道某個消息是否被進程收到,必須向該進程發送一個消息并等待回復。

            Erlang 中的并發編程只需要如下幾個簡單的函數。

            Pid = spawn(Mod,Func, Args) 
            創建一個新的并發進程來執行Mod模塊中的 Fun(),Args 是參數。

            Pid ! Message 
            想序號為 Pid 的進程發送消息。消息發送是異步的,發送方不等待而是繼續之前的工作。

            receive… end 
            接受發送給某個進程的消息,匹配后處理。

            receive
                Pattern 1 [when Guard1] ->
                    Expression1;
                Pattern 2 [when Guard2] ->
                    Expression2;
                ...
                after T ->
                    ExpressionTimeout
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8

            某個消息到達后,會先與 Pattern 進行匹配,匹配相同后執行,若未匹配成功消息則會保存起來待以后處理,進程會開始下一輪操作,若等待超時 T,則會執行表達式 ExpressionTimeout。

            舉個例子: 
            現在我們要進行兩個進程的消息傳遞,一個進程發送Num1 和 Num2以及對應的操作標識,另外一個進程接受到消息后計算。 
            比如 {plus, Num1, Num2} 就是求 Num1 和 Num2 的和。

            -module(calculate).
            -export([loop/0, start/0]).
            
            % 創建新進程,并執行 loop 函數。
            start() -> spawn(calculate, loop, []).
            
            % loop 函數
            loop() ->
                receive                     % 接受消息并進行匹配
                    {plus, Num1, Num2} ->   % 匹配加法
                        io:format("Num1 plus Num2 result:~p~n", [Num1 + Num2]),
                        loop();
                    {reduce, Num1, Num2} -> % 匹配減法
                        io:format("Num1 reduce Num2 result:~p~n", [Num1 - Num2]),
                        loop();
                    {multi, Num1, Num2} ->  % 匹配乘法
                        io:format("Num1 multi Num2 result:~p~n", [Num1 * Num2]),
                        loop();
                    {divis, Num1, Num2} ->  % 匹配除法
                        io:format("Num1 divis Num2 result:~p~n", [Num1 div Num2]),
                        loop()
                after 50000 ->              % 超時操作
                          io:format("timeout!!")
                end().
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21
            • 22
            • 23
            • 24
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
            • 7
            • 8
            • 9
            • 10
            • 11
            • 12
            • 13
            • 14
            • 15
            • 16
            • 17
            • 18
            • 19
            • 20
            • 21
            • 22
            • 23
            • 24

            執行結果:

            這里寫圖片描述

            我們一行一行來看。

            第一行(標號為 1>),編譯 calculate.erl。

            第二行,執行 calculate 模塊中的 start 函數并且創建進程,創建后將進程的 Pid 賦值給 Pid1。

            第三行,打印 Pid1。

            第四行,創建 Pid2 的進程并且向 Pid1 進程發送請求消息,計算 Num1 和 Num2 的和,Pid1 進程計算完畢后并打印。

            第五行,計算減法并打印。

            第六行,報錯因為 Pid3 已經被使用,在 Erlang 中變量賦值一次后就不能被改變了,不會變就不會出現多個進程修改導致不一致問題。

            第七行,計算乘法并打印結果。

            第八行,計算除法并打印結果。

            最后,超時發生錯誤。

            由此可見 Erlang 并發編程也非常簡單且符合人們的思維。

            這篇文章就簡單地介紹到這里,希望有所幫助^_^。

            posted on 2016-12-16 12:20 思月行云 閱讀(559) 評論(0)  編輯 收藏 引用 所屬分類: Erlang
            亚洲国产高清精品线久久 | 久久精品国产网红主播| 久久国产成人精品国产成人亚洲| 激情综合色综合久久综合| 久久国产精品一区| 无码国产69精品久久久久网站| 久久精品国产亚洲av麻豆色欲| 欧美精品一本久久男人的天堂| 国产精品亚洲综合久久| 精品乱码久久久久久久| 久久强奷乱码老熟女网站| 青青草原精品99久久精品66 | 精品久久久久久久中文字幕| 亚洲国产精品综合久久网络| 久久99精品久久久久久hb无码| 国内精品久久久久影院网站| 精品人妻久久久久久888| 狠狠色丁香久久婷婷综合蜜芽五月 | 久久综合九色综合97_久久久| 青草影院天堂男人久久| 久久人人添人人爽添人人片牛牛| 久久久久久狠狠丁香| 人妻精品久久无码专区精东影业| 久久亚洲国产成人精品无码区| 99久久无色码中文字幕| 久久精品极品盛宴观看| 久久99精品久久久久久9蜜桃| MM131亚洲国产美女久久| 热re99久久6国产精品免费| 日韩精品久久久久久久电影| 久久久青草青青国产亚洲免观| 国产精品无码久久久久| 久久综合九色综合精品| 九九久久99综合一区二区| 国产精品视频久久久| 久久亚洲AV成人无码国产| 三上悠亚久久精品| 国内精品人妻无码久久久影院| 精品综合久久久久久888蜜芽| 久久久无码一区二区三区| 久久精品国产亚洲AV高清热 |