青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2017年1月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234


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

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 220943
  • 排名 - 117

最新評論

閱讀排行榜

http://www.cnblogs.com/zhengsyao/p/erlang_race_condition_in_digraph.html
雖然 Erlang 的廣告說得非常好,functional、share-nothing、消息傳遞,blah blah 的,好像用 Erlang 寫并發程序就高枕無憂了,但是由于 Erlang 信奉高度實用主義的哲學,所以 Erlang 中有各種各樣的后門,使得 Erlang 是一個不那么 pure 的 functional 語言,而且也是允許 share something 的。

比如說,ETS 就是一個大后門。ETS 本是為實現 Mnesia 數據庫而實現的一個“基于哈希表的無結構化 term 存儲”,但是 ETS 太好用了,能滿足高性能的字典需求,而且還可以全局訪問,完全擺脫 Erlang 設置的 share nothing、immutable variable 之類的 functional 束縛,所以很多程序會喜歡使用 ETS。

Erlang 的(為了避免錯誤而設置的)種種約束在這些使用了這些后門的情況下也會喪失威力。這不,我在標準庫的 digraph 模塊中就發現了一個潛在的 bug。下面先說一下使用 ETS 造成并發 bug 的模式,然后再看 digraph 中的這個潛在 bug。

Erlang 中有很多這樣的代碼:V2 = do_something(V1),如果 V1 和 V2 是同樣類型的復雜數據結構,根據 Erlang 的語義,do_something 對 V1 只是讀操作,然后生成新的字段,最后創建出新的 V2 返回,V1 應該是不動的。這樣其他進程也可以放心地訪問 V1,至少 V1 的狀態在系統中是一致的(consistent)。如果 V1 中使用了 ETS,并且 do_something 對 ETS 做操作了,那么這個函數就產生副作用了,以上的一致性可能就無法保證了,例如假設 V1 是這樣的數據結構:

-record(some_struct, {tab1 =  ets:tab(),
                      tab2 =  ets:tab(),
                      var1 =  integer()}).

這個數據結構中有兩個 ETS 表,說明這個數據結構的狀態是由兩個 ETS 表的狀態決定的。雖然 Erlang 運行時能保證單個 ETS 表的并發訪問,但是多個表的一致性還需要程序自己來維護,因此這個數據結構在多進程訪問的情況下就會出現競爭條件。下面我們看看 digraph 模塊中的潛在 bug。

digraph 模塊是用來表示有向圖(directed graph)的。有向圖就是在一個圖中,要考慮邊(edge)中頂點(vertex)的順序。有向圖的數據結構中要保存頂點的集合以及邊的集合。某個頂點的鄰居(neighbour)指的是和這個頂點相連的頂點,由于有向圖是有方向的,所以一個頂點會有入鄰居(in-neighbour)和出鄰居(out-neighbour),前者指的是有邊射入當前頂點的頂點,后者指的是當前頂點有邊射出到的頂點。好了這是基本概念。下面我們看 digraph 模塊使用的數據結構:

1 -record(digraph, {vtab = notable :: ets:tab(),
2                   etab = notable :: ets:tab(),
3                   ntab = notable :: ets:tab(),
4                   cyclic = true  :: boolean()}).

digraph 記錄體中連續 3 個 ETS 表,看上去就有不好的事情可能發生。vtab 是頂點的表,etab 是邊的表,ntab 維護了鄰居的關系。digraph 模塊對 digraph 數據結構并發訪問做了控制,允許設置兩種模式:protected 和 private。前者只允許 digraph 的所有者進程修改,但是其他進程都可以訪問;后者只允許所有者進程修改和訪問,其他進程不能訪問(其實就是設置了 ETS 表的訪問權限)。

下面創建一個簡單的有向圖,創建幾個節點和邊:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
5> DG = digraph:new().       
{digraph,28692,32789,36886,true}
6> digraph:add_vertex(DG, v1).
v1
省略...
11> digraph:add_edge(DG, v1, v2).
['$e'|0]
省略...
16> digraph:in_neighbours(DG, v1).
[]
17> digraph:in_neighbours(DG, v2).
[v1]
省略...
21> digraph:out_neighbours(DG, v1).
[v5,v4,v3,v2]

命令 5> 創建了新的 digraph,輸出的 DG 值中包含了幾個 ETS id,然后添加頂點和邊。v1 頂點的入鄰居沒有,出鄰居包括 v2、v3、v4 和 v5。下面展示了這幾個 ETS 表中的項:

vertices 表中是頂點,edges 表中是邊,neighbour 表中保存了 in 和 out 的關系。其實 neighbour 表中的內容可以從 edges 表中推導出來,但是這個表在這里可以做一個緩存作用,迅速查出一個節點的鄰居關系,而不用掃描 edges 表。

從這里我們應該可以嗅到 bug 的味道了:edges 表和 neighbour 表有映射關系,如果修改一個表,那么另一個表也需要修改,否則就會出現數據不一致(inconsistent)的情況。我們來看插入邊的代碼:

復制代碼
 1 add_edge(G, V1, V2) ->
 2     do_add_edge({new_edge_id(G), V1, V2, []}, G).
 3 
 4 do_add_edge({E, V1, V2, Label}, G) ->
 5     case ets:member(G#digraph.vtab, V1) of
 6         false -> {error, {bad_vertex, V1}};
 7         true  ->
 8             case ets:member(G#digraph.vtab, V2) of
 9                 false -> {error, {bad_vertex, V2}};
10                 true ->
11                     case other_edge_exists(G, E, V1, V2) of
12                         true -> {error, {bad_edge, [V1, V2]}};
13                         false when G#digraph.cyclic =:= false ->
14                             acyclic_add_edge(E, V1, V2, Label, G);
15                         false ->
16                             do_insert_edge(E, V1, V2, Label, G)
17                     end
18             end
19     end.
20 
21 do_insert_edge(E, V1, V2, Label, #digraph{ntab=NT, etab=ET}) ->
22     ets:insert(NT, [{{out, V1}, E}, {{in, V2}, E}]),
23     ets:insert(ET, {E, V1, V2, Label}),
24     E.
復制代碼

diagraph:add_edge/3 是發布的接口,do_add_edge/2 做一些頂點是否存在的判斷,檢查是否能添加邊,最后 do_insert_edge/5 真正負責把邊插入相應的 ETS 表。可以看出,第 22 行插入鄰居表,第 23 行插入邊表。

這里就可能出現問題了:根據 Erlang 調度器的規則,第 22 行執行完成之后,由于 ets:insert/2 是一個 BIF 調用,因此進程有可能會被搶占。如果此時進程被搶占,那么 digraph 就處于一個 inconsistent 狀態了。如下圖所示:

假設這個 digraph 是 protected,那么其他進程是可以訪問的。如果其他進程需要 joint 訪問這兩個表的話,有可能就會出問題。果然,訪問鄰居的接口 digraph:in_neighbours/2 就是這樣一個函數,下面來看代碼:

復制代碼
 1 in_neighbours(G, V) ->
 2     ET = G#digraph.etab,
 3     NT = G#digraph.ntab,
 4     collect_elems(ets:lookup(NT, {in, V}), ET, 2).
 5 
 6 collect_elems(Keys, Table, Index) ->
 7     collect_elems(Keys, Table, Index, []).
 8 
 9 collect_elems([{_,Key}|Keys], Table, Index, Acc) ->
10     collect_elems(Keys, Table, Index,
11           [ets:lookup_element(Table, Key, Index)|Acc]);
12 collect_elems([], _, _, Acc) -> Acc.
復制代碼

in_neighbours/2 先提取出兩個表 ET 和 NT,分別是邊表和鄰居表,然后調用 collect_elems/3,相當于做一個 joint 查詢。第 4 行首先查詢鄰居表 ets:lookup(NT, {in, V}),也就是在鄰居表中查詢節點 V 入邊。查到邊之后,collect_elems/4 的第 11 行再從邊表中去查這條邊的頂點。那么如果出現上圖中的情況,在添加邊的時候在鄰居表中插入完成之后進程被切出,那么 edges 表中的第 4 行還不存在,而 neighbours 表中圈出的那兩行是存在的。那么 collect_elems/4 執行到 11 行的 ets:lookup_element 就會拋出異常。

以上就是在標準庫的 digraph 模塊中發生競爭條件的一個例子。對于這個具體的問題來說,把 do_insert_edge/5 中那兩行 insert 換一下位置就好了,先插入邊表,再插入鄰居表,畢竟后面的表可以由前面的表推導出來,所以在訪問的時候先訪問后面的表在訪問前面的表不會出現查不到的情況,盡管本質上看數據還是有可能不一致。所以雖然可以修掉這個 bug,但是這種風格還是有風險的,比如說有 3 個或更多的表需要一致的情況。其實 digraph 模塊這種風格:創建一個數據結構,得到一個句柄,然后大家都可以修改和訪問的風格不是非常“Erlangic”。應該是像這樣的設計:DG = digraph:new(), DG1 = digraph:add_vertex(DG, v1)... 。也就是說,每次修改之后就產生一個新的變量。當然,這樣在內部就不能用 ETS 來實現了,因為每次修改的是 ETS 表,而 DG 變量綁定的 #digraph{} 里面的表 id 字段的值又沒變,所以 DG 和 DG1 的值實際還是一樣的,只是表示的意義不同了,可怕的副作用啊。

至于這是不是 bug,可能有人會爭論了:至少 ETS 查詢會拋 badarg 啊,然后這個異常會傳播到 in_neighours/2 的調用者啊,所以在調用的時候要捕捉異常啊。可是 digraph 文檔又沒說會拋異常,看源碼的時候,也沒有語法結構注明一個函數會拋什么異常,那我怎么知道什么時候要捉異常呢?就算我養成調什么函數都捉異常的習慣,可是我捉到了異常又怎么知道是怎么回事呢?特別是這種并發相關的問題,下次復現的幾率又像中獎一樣。所以 Erlang 這門語言真是讓人又愛又恨啊。

不過不爭論語言本身了,言歸正傳,本文的結論就是:在使用 ETS 的時候要注意 ETS 是全局共享的內存,要注意數據一致性的問題。



erlang 參數傳遞時是賦值or引用?
請教一個基礎問題,erlang 參數傳遞時是賦值or引用?
找不到方法測試。
求教了。

答:
erlang 中怎么會有引用這種說法,變量都是拷貝過去的。

問:
無法實現引用,是么?
我在寫的東西要傳一個大狀態。
所以疑惑了一下。

答:
erlang 所有的變量都只能在函數中傳遞,沒有全局變量這一說。
你傳遞狀態是通過改變函數參數實現的


問:
我不是很清楚當參數很大時,進行拷貝的效率如何.
能給我解惑一下么?


越大效率越低
另外是原子atom ,erlang 的垃圾回收機制是不回收的,除非運行結束。

問:
試想gen_server中call(_From,Status,Args)被調用時,Status就被改變了。這是不是意味著這里的Status是被引用傳遞進去的呢
我有闡述清楚么?


答:
不會
Status 
的值
不會被函數改變
函數得到的只是一個新的參數邦定
綁定

簡單的說
erlang 的參數都是拷貝方式的


廣州-手  14:54:35
對,這就是內存共享。

返源
不見得多少,你的每一個函數結束就會回收當中的內存。
不存在引用

廣州-手   14:53:52
沒有引用的參數傳遞 不知會吃掉我程序的性能

上海-PHP-返源   14:54:34
如果有引用就有副作用
就沒辦法獨自運行

廣州-手   14:54:10
不知會吃掉多少性能。
但是我的status是一條很長的記錄。

廣州-手 )  14:55:23
稍稍有點擔憂。暫時還不能測試。
廣州-手   14:56:23
你剛說的參數 愈大效率越低,是怎么回事?
上海-PHP-返源   14:57:02
記錄是單獨存儲的
不過你傳遞的時候還是拷貝

廣州-手   14:56:47
恩。


上海-PHP-返源    14:57:40
但這里具體內部實現有很多方案
譬如你不寫,只是取,我就可以共用內存。

廣州-手    14:58:03
怎么實現,求指導。

上海-PHP-返源    14:58:56
這個跟你實現沒關系哈,我說的erlang 內部。
總之你減少參數的大小
有利提高速度

廣州-手   14:58:57
這個意思是erlang的自動優化么?

上海-PHP-返源    14:59:40

是的

本文轉自Erlang中國(www.erlangchina.NET
原文網址:http://www.erlangchina.Net/thread-845-1-1.html


 

posted on 2017-01-15 17:17 思月行云 閱讀(313) 評論(0)  編輯 收藏 引用 所屬分類: Erlang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲综合色激情五月| 国产亚洲欧美日韩美女| 亚洲伊人伊色伊影伊综合网 | 国产视频观看一区| 久久视频国产精品免费视频在线 | 国产亚洲精品久久飘花| 欧美一区二区三区四区在线| 亚洲日本激情| 99精品视频免费| 亚洲国产导航| 99精品国产热久久91蜜凸| 国产精品一区二区久久精品| 欧美电影免费观看高清完整版| 亚洲精品资源美女情侣酒店| 亚洲精品你懂的| 亚洲一区欧美| 亚洲麻豆视频| 日韩视频在线你懂得| 精品9999| 亚洲国产综合视频在线观看| 激情综合五月天| 亚洲国产精品精华液网站| 国产日韩欧美三级| 欧美国产亚洲另类动漫| 国产精品国产三级国产aⅴ入口| 欧美大尺度在线| 欧美精品一区二区三区一线天视频 | 欧美成人免费在线视频| 国产精品免费看片| 亚洲开发第一视频在线播放| 亚洲一区二区欧美| 欧美在线观看一区二区三区| 亚洲先锋成人| 日韩视频一区二区三区在线播放免费观看| 一区二区三区产品免费精品久久75 | 午夜精品区一区二区三| 久久女同精品一区二区| 免费久久精品视频| 国产精品久久97| 亚洲欧洲在线一区| 久久黄色级2电影| 亚洲影院高清在线| 欧美精品在线免费播放| 国产精品网站在线观看| 国产欧美在线视频| 蜜桃久久av| 久久精品国产清高在天天线| 国产精品久久久久一区| 亚洲国产成人久久| 亚洲综合另类| 亚洲欧美不卡| 国语对白精品一区二区| 欧美中文字幕在线视频| 91久久久久久国产精品| 久久在线91| 麻豆精品在线观看| 日韩视频在线观看免费| 欧美sm视频| 美女被久久久| 久久久久久欧美| 久久精品视频免费| 国产精品久久久久三级| 亚洲欧美日韩在线| 99亚洲伊人久久精品影院红桃| 欧美日韩免费| 久久国产精品一区二区三区四区| 亚洲欧美日韩在线综合| 国产精品久久久久久久浪潮网站 | 一区二区三区精品视频在线观看| 欧美日韩免费观看中文| 亚洲一区日韩在线| 欧美一区在线直播| 亚洲欧美日韩天堂| 国产精品久久久久国产精品日日| 亚洲欧美日韩在线观看a三区| 日韩视频第一页| 国产精品久久久久久av福利软件| 欧美高清视频一区| 国产欧美一区在线| 模特精品在线| 国产精品超碰97尤物18| 日韩午夜电影在线观看| 亚洲高清精品中出| 亚洲私人黄色宅男| 一区二区激情小说| 久久se精品一区精品二区| 欧美亚洲自偷自偷| 99国产麻豆精品| 国产亚洲a∨片在线观看| 欧美精品综合| 亚洲日本视频| 亚洲激情成人网| 欧美一区二区三区另类| 亚洲国产另类 国产精品国产免费| 91久久国产自产拍夜夜嗨| 在线观看日韩国产| 亚洲综合视频在线| 欧美成人精品高清在线播放| 欧美日韩精品国产| 久久精品动漫| 亚洲电影视频在线| 欧美大片第1页| 亚洲线精品一区二区三区八戒| 亚洲一区二区在线看| 国产欧美一级| 欧美日韩成人综合在线一区二区| 亚洲娇小video精品| 亚洲综合激情| 亚洲国产经典视频| 欧美日韩精品国产| 美日韩在线观看| 欧美在线视频观看| 亚洲最快最全在线视频| 免费精品视频| 亚洲欧洲一区二区三区在线观看 | 久久九九电影| 亚洲高清在线播放| 亚洲激情婷婷| 午夜精品久久久久久久白皮肤| 久久另类ts人妖一区二区| 久久视频这里只有精品| 亚洲国产天堂网精品网站| 午夜欧美大尺度福利影院在线看| 欧美日韩国产不卡| 香蕉乱码成人久久天堂爱免费| 国产在线精品二区| 最近中文字幕mv在线一区二区三区四区 | 久久久夜夜夜| 日韩午夜高潮| 美女网站在线免费欧美精品| 欧美一区二区三区久久精品| 亚洲一区观看| 欧美亚洲综合在线| 午夜精品久久久久久久久久久久久| 亚洲激情六月丁香| 亚洲国产精品成人精品| 亚洲精品欧美日韩专区| 欧美午夜精品理论片a级按摩| 久久精品99国产精品| 亚洲天堂偷拍| 久久久99免费视频| 久久中文欧美| 国产一区二区三区黄视频| 国产丝袜一区二区三区| 午夜精品视频在线| 久久精品日韩欧美| 国产精品毛片a∨一区二区三区| 国产欧美在线看| 亚洲午夜久久久| 久久精品欧美| 亚洲第一视频网站| 香蕉亚洲视频| 欧美日韩在线观看视频| 欧美中文字幕在线观看| 久久尤物电影视频在线观看| 久久这里有精品视频| 国产精品成人一区二区三区吃奶| 国产欧美日韩精品丝袜高跟鞋| 加勒比av一区二区| 亚洲午夜高清视频| 亚洲国产精品久久久久秋霞影院| 亚洲高清资源| 美女亚洲精品| 中日韩男男gay无套| 久久免费视频网站| 欧美午夜精彩| 午夜视频在线观看一区| 久久精品国产久精国产思思| 久久色中文字幕| 中文av一区特黄| 久久www免费人成看片高清| 午夜精品在线观看| 久久久久国产精品一区二区| 欧美电影在线| 日韩一级成人av| 久久综合五月天婷婷伊人| 欧美日韩精品久久久| 欧美日韩国产在线观看| 国产精品一区免费观看| 在线视频亚洲一区| 香蕉久久a毛片| 欧美片在线观看| 海角社区69精品视频| 亚洲欧美日韩国产成人精品影院| 亚洲欧美日韩中文在线制服| 欧美在线播放高清精品| 久久精品在线| 精东粉嫩av免费一区二区三区| 欧美日韩国产综合视频在线观看中文 | 中文无字幕一区二区三区| 亚洲精品激情| 国产日韩欧美成人| 亚洲天堂av在线免费观看| 欧美激情第五页| 国产精品影片在线观看| 毛片一区二区| 久久久亚洲成人| 欧美黑人多人双交| 欧美电影在线| 久久久综合激的五月天|