[Erlang-0003][OTP] Efficiency Guide User's Guide - Common Caveats
生活随笔
收集整理的這篇文章主要介紹了
[Erlang-0003][OTP] Efficiency Guide User's Guide - Common Caveats
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
原文鏈接:http://www.erlang.org/doc/efficiency_guide/commoncaveats.html (水平有限,錯誤之處歡迎指正) ? 3 一般說明
這里列出一些需要注意的模塊和內(nèi)建函數(shù),這里不只關(guān)注性能,還有其他。 ? 3.1 timer模塊
用erlang:send_after/3和erlang:start_time/3創(chuàng)建的定時器,遠(yuǎn)比timer模塊創(chuàng)建的定時器高效得多。timer模塊用單獨的進(jìn)程管理定時器,如果大量進(jìn)程經(jīng)常性的創(chuàng)建和注銷定時器,這個進(jìn)程很容易過載(尤其在使用SMP虛擬機(jī)的時候)。
有些timer模塊的函數(shù)不涉及定時器(例如timer:tc/3,timer:sleep/1),他們不會call timer_server進(jìn)程,因此是無害的。 ? 3.2 list_to_atom/1
原子不參與垃圾回收。一旦原子被創(chuàng)建,就永遠(yuǎn)不會消失。如果原子數(shù)量達(dá)到上限(默認(rèn)1048576),虛擬機(jī)會終止。
因此,隨意將字符串轉(zhuǎn)換成原子對需要持續(xù)運(yùn)行的系統(tǒng)來說是非常危險的。如果只允許輸入某些被定義好的原子,可以使用list_to_existing_atom/1來避免“拒絕服務(wù)攻擊”。(所有被允許的原子必須已經(jīng)被創(chuàng)建,例如在一個模塊中使用它們,并且加載這個模塊。)
使用list_to_atom/1去構(gòu)建一個原子,并像下面這樣這樣傳遞給apply/3,代價非常高,在時間要求嚴(yán)格的代碼中不被推薦。 apply(list_to_atom("some_prefix"++Var), foo, Args) ? 3.3 length/1
計算列表長度的時間和列表長度成正比,相反tuple_size/1,byte_size/1和bit_size/1的執(zhí)行時間是一個常量。
通常你不需要擔(dān)心length/1的速度,因為它是用C高效實現(xiàn)的。但在一些時間要求嚴(yán)格的代碼中,如果輸入的列表可能非常長,你就要避免使用length/1。
一些length/1可以用匹配來替換,例如代碼
foo(L) when length(L) >= 3 ->... 可寫作 foo([_,_,_|_]=L) ->... (一個明顯的不同是,如果L不是一個合法的列表,length(L)會失敗,而在第二個代碼片段中的匹配卻不會。) ? 3.4 setelement/3
setelement/3會拷貝它所修改的元組,因此,在循環(huán)中用setelement/3更新元組每次都會拷貝這個元組。
以上規(guī)則有個例外,就是這個元組被拷貝過。如果編譯器能夠明顯的分辨出直接更新和拷貝一份更新是完全一樣的,那么setelement/3調(diào)用將被替換成一個特別的破壞性的setelement命令。
multiple_setelement(T0) ->T1 = setelement(9, T0, bar),T2 = setelement(7, T1, foobar),setelement(5, T2, new_value).
第一次setelement/3調(diào)用會拷貝元組,并改變第九個元素。緊接著第二個setelement/3調(diào)用會改變剛才拷貝的那個元組。
要使這個優(yōu)化被應(yīng)用,一下所有情況都必須滿足:
size/1返回元組和binary的大小。
用R12B引進(jìn)的新的內(nèi)建函數(shù)tuple_size/1和byte_size/1為編譯器和運(yùn)行時系統(tǒng)提供更多的優(yōu)化機(jī)會。更大的好處是新的內(nèi)建函數(shù)可以幫助Dialyzer找到程序中更多的bugs。 ? 3.6 split_binary/2
通常用匹配來分割一個二進(jìn)制比調(diào)用split_binary/2函數(shù)更高效,此外將位語法的匹配和split_binary/2混合使用將妨礙位語法匹配的優(yōu)化。
DO <<Bin1:Num/binary,Bin2/binary>> = Bin, DO NOT {Bin1,Bin2} = split_binary(Bin, Num)
3.7 '--'操作符
注意:'--'操作符與其操作對象的長度的乘積成正比,也就是說,如果兩個操作對象都是長列表,速度會很慢。
用ordsets模塊代替:
DO HugeSet1 = ordsets:from_list(HugeList1), HugeSet2 = ordsets:from_list(HugeList2), ordsets:subtract(HugeSet1, HugeSet2) 明顯的,如果列表的原始順序很重要,這種方法是不可行的。如果列表的順序必須被保留,就這樣做: DO Set = gb_sets:from_list(HugeList2), [E || E <- HugeList1, not gb_sets:is_element(E, Set)] 細(xì)節(jié)注意1:如果列表中有重復(fù)的元素,那這段代碼和'--'是不同的(這段代碼會刪掉HugeList1中所有在HugeList2中出現(xiàn)的元素;'--'只刪除對應(yīng)個數(shù)。)
細(xì)節(jié)注意2:這段代碼用'=='比較操作對象,而'--'用'=:='比較。如果對差別的精度要求高,可以用sets代替gb_sets,但是sets:from_list/1處理長列表比gb_sets:from_list/1慢很多。
用'--'操作符少出列表中的一個元素不存在性能問題: OK HugeList1 -- [Element]
這里列出一些需要注意的模塊和內(nèi)建函數(shù),這里不只關(guān)注性能,還有其他。 ? 3.1 timer模塊
用erlang:send_after/3和erlang:start_time/3創(chuàng)建的定時器,遠(yuǎn)比timer模塊創(chuàng)建的定時器高效得多。timer模塊用單獨的進(jìn)程管理定時器,如果大量進(jìn)程經(jīng)常性的創(chuàng)建和注銷定時器,這個進(jìn)程很容易過載(尤其在使用SMP虛擬機(jī)的時候)。
有些timer模塊的函數(shù)不涉及定時器(例如timer:tc/3,timer:sleep/1),他們不會call timer_server進(jìn)程,因此是無害的。 ? 3.2 list_to_atom/1
原子不參與垃圾回收。一旦原子被創(chuàng)建,就永遠(yuǎn)不會消失。如果原子數(shù)量達(dá)到上限(默認(rèn)1048576),虛擬機(jī)會終止。
因此,隨意將字符串轉(zhuǎn)換成原子對需要持續(xù)運(yùn)行的系統(tǒng)來說是非常危險的。如果只允許輸入某些被定義好的原子,可以使用list_to_existing_atom/1來避免“拒絕服務(wù)攻擊”。(所有被允許的原子必須已經(jīng)被創(chuàng)建,例如在一個模塊中使用它們,并且加載這個模塊。)
使用list_to_atom/1去構(gòu)建一個原子,并像下面這樣這樣傳遞給apply/3,代價非常高,在時間要求嚴(yán)格的代碼中不被推薦。 apply(list_to_atom("some_prefix"++Var), foo, Args) ? 3.3 length/1
計算列表長度的時間和列表長度成正比,相反tuple_size/1,byte_size/1和bit_size/1的執(zhí)行時間是一個常量。
通常你不需要擔(dān)心length/1的速度,因為它是用C高效實現(xiàn)的。但在一些時間要求嚴(yán)格的代碼中,如果輸入的列表可能非常長,你就要避免使用length/1。
一些length/1可以用匹配來替換,例如代碼
foo(L) when length(L) >= 3 ->... 可寫作 foo([_,_,_|_]=L) ->... (一個明顯的不同是,如果L不是一個合法的列表,length(L)會失敗,而在第二個代碼片段中的匹配卻不會。) ? 3.4 setelement/3
setelement/3會拷貝它所修改的元組,因此,在循環(huán)中用setelement/3更新元組每次都會拷貝這個元組。
以上規(guī)則有個例外,就是這個元組被拷貝過。如果編譯器能夠明顯的分辨出直接更新和拷貝一份更新是完全一樣的,那么setelement/3調(diào)用將被替換成一個特別的破壞性的setelement命令。
multiple_setelement(T0) ->T1 = setelement(9, T0, bar),T2 = setelement(7, T1, foobar),setelement(5, T2, new_value).
第一次setelement/3調(diào)用會拷貝元組,并改變第九個元素。緊接著第二個setelement/3調(diào)用會改變剛才拷貝的那個元組。
要使這個優(yōu)化被應(yīng)用,一下所有情況都必須滿足:
- 索引(setelement/3的第一個參數(shù))必須寫成整數(shù),不是變量和表達(dá)式。
- 索引必須是倒序給出的。
- 在setelement/3的調(diào)用之間不能有其他函數(shù)的調(diào)用。
- 從setelement/3返回的元組必須只被用作后續(xù)的setelement/3調(diào)用。
?
如果不能像例子multiple_setlement/1一樣構(gòu)造代碼,修改大元組的最好方法是把元組轉(zhuǎn)換成列表,修改后,再轉(zhuǎn)換回元組。 ? 3.5 size/1size/1返回元組和binary的大小。
用R12B引進(jìn)的新的內(nèi)建函數(shù)tuple_size/1和byte_size/1為編譯器和運(yùn)行時系統(tǒng)提供更多的優(yōu)化機(jī)會。更大的好處是新的內(nèi)建函數(shù)可以幫助Dialyzer找到程序中更多的bugs。 ? 3.6 split_binary/2
通常用匹配來分割一個二進(jìn)制比調(diào)用split_binary/2函數(shù)更高效,此外將位語法的匹配和split_binary/2混合使用將妨礙位語法匹配的優(yōu)化。
DO <<Bin1:Num/binary,Bin2/binary>> = Bin, DO NOT {Bin1,Bin2} = split_binary(Bin, Num)
3.7 '--'操作符
注意:'--'操作符與其操作對象的長度的乘積成正比,也就是說,如果兩個操作對象都是長列表,速度會很慢。
DO NOT
HugeList1 -- HugeList2用ordsets模塊代替:
DO HugeSet1 = ordsets:from_list(HugeList1), HugeSet2 = ordsets:from_list(HugeList2), ordsets:subtract(HugeSet1, HugeSet2) 明顯的,如果列表的原始順序很重要,這種方法是不可行的。如果列表的順序必須被保留,就這樣做: DO Set = gb_sets:from_list(HugeList2), [E || E <- HugeList1, not gb_sets:is_element(E, Set)] 細(xì)節(jié)注意1:如果列表中有重復(fù)的元素,那這段代碼和'--'是不同的(這段代碼會刪掉HugeList1中所有在HugeList2中出現(xiàn)的元素;'--'只刪除對應(yīng)個數(shù)。)
細(xì)節(jié)注意2:這段代碼用'=='比較操作對象,而'--'用'=:='比較。如果對差別的精度要求高,可以用sets代替gb_sets,但是sets:from_list/1處理長列表比gb_sets:from_list/1慢很多。
用'--'操作符少出列表中的一個元素不存在性能問題: OK HugeList1 -- [Element]
?
? (原創(chuàng)翻譯,歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處:http://www.cnblogs.com/liangjingyang/archive/2012/06/20/2557065.html)轉(zhuǎn)載于:https://www.cnblogs.com/liangjingyang/archive/2012/06/20/2557065.html
總結(jié)
以上是生活随笔為你收集整理的[Erlang-0003][OTP] Efficiency Guide User's Guide - Common Caveats的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6410 gpio控制及接口
- 下一篇: 初步认识注册表(待续)