[Erlang 學習筆記] Erlang開發建議
以下是在erlang專案開發中的一些記錄,即包含很多通俗易懂的原則,也包含一些似是而非的建議,比較混亂,還沒有積累到一個可以分門別類的地步,各位就將就看吧..
:)
* 確保沒有任何編譯警告
* Erlang中String採用list實現,32位系統中,其1個字元用8個位元組的空間(4個儲存value, 4個儲存指標)。因此string速度較慢,空間佔用較大
* 在Server中,總是盡力書寫尾遞迴(tail-recursive)的函式
* 使用'++'時,left list會被拷貝,然後新增到right list的頭部,因此最好把length較短的list放在左側
* 避免使用regexp,如果需要正規表示式,請使用re
* timer模組的大部分函式實現,依賴於一個process,如果過多使用timer,會導致這個process負載過大,影響效率。
推薦使用erlang:send_after/3及erlang:start_timer/3
* 避免使用list_to_atom/1,因為erlang中atom數量最大為1048576, 且不進行GC控制。因此如果持續性的呼叫list_to_atom/1
可能很容易達到系統上限,從而導致emulator terminate。請使用list_to_existing_atom/1。
* list內部實現為一個列表,因此length(List), 需要遍歷整個list比較耗時
* 對於不同的資料型別,使用不同的size函式:tuple_size/1, byte_size/1, bit_size/1
* 使用binary match來進行binary的分割,而不使用split_binary/2
* 如果兩個list都擁有很多資料,那麼請不要使用'--',而是將資料轉化到ordsets,然後呼叫ordsets:substract/2.
* 對於binary相關操作可以進行binary優化(bin_opt_info編譯選項)程式碼框架:
* f(<<Pattern1,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
...
f(<<>>, ...) ->
ReturnValue.
* 呼叫lists:flatten/1可以將list扁平化,這個操作代價很大,比'++'還要昂貴。下面這些時候我們可以避免:
將資料傳送給port時
呼叫list_bo_binary/1和iolist_to_binary前
* 小的函式可以讓您方便的找出錯誤的函式和程式碼
* 不要在同一行出現相同的符號
20 some_fun() ->
21 L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22 ...
編譯時,會提示line 21 '[' 語法錯誤, 因為21行有多個 '[' ,所以這個bug不能準確定位,你需要花時間去排查程式碼。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
這樣,編譯其會提示你 line 22 '[' 語法錯誤,你很開就知道是那個地方錯了。
* 使用 CTRL + / 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 彈出選單選項,可以選擇是否退出Erlang。
其中CTRL + G可以用來連線其他的shell, CTRL + C可以檢視其他一些系統資訊
Ctrl + C abort 是野蠻的退出方式
* use "open_port({fd,0,2}, [out])" make erlang program write standard error to unix system
* If you don't run experiments before you start designing a new system, your entire system will be an experiment!
* standard data structure desc:
Module Description
sets sets, i.e. a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables
Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our select : list | ets | gb_tree
* 通過code:clash/0 檢測程式碼中是否有module衝突現象(sticky)
* epmd -d -d 啟動 epmd 可以檢視erlang node之間的通訊
* 將正常的邏輯程式碼和錯誤處理程式碼分離,發生錯誤時,儘管錯誤。由另一個錯誤處理模組進行處理
* 類似於作業系統,我們的程式也可以分為kernel 和 user 兩層, 對於kernel絕對不能出現錯誤, 對於user可以出現錯誤,進行恢復
* process頂層loop涉及的程式碼及函式,最好在一個module中實現
* process 的register name和module名稱一致, 便於尋找程式碼
* 每個process具有一個單一的角色,比如:supervisor 用來進行錯誤恢復, work 工作者,可以出現錯誤, trusted worker 不會出現錯誤
* 通過函式呼叫可以實現的功能,就不要使用sever實現(如gen_server, 及類似的loop 實現)
* 給訊息加一個tag,在發生錯誤的時候,可以定位到訊息,同時也有利於程式的穩健
* 在訊息迴圈中,對於unknown的訊息,請呼叫lib:flush_receive/0 將其清除,減輕process msg queue的長度
* server中總是書寫尾遞迴的迴圈
* 儘量使用record, 而不是原始的tuple來表現資料結構, 在使用record時,使用select match:
#person{name = Name, age = Age} = Person
* 對於返回值,最好也新增一個tag,用來說明返回值型別,或者執行成功與否
* 儘可能少的使用catch和try,在erlang程式中,不推薦主動捕獲異常。只有當我們的邏輯特別複雜,我們可以使用throw來返回資料,使用catch來獲取返回值。
* 當然程式與外界互動,外界資料不可靠時,需要使用catch和try
* 慎重使用process dictory, 當你使用get/1, put/1時,你的應用會具有很大的slide effect。可以通過加入一個新的引數來儲存原本需要儲存到process dictory中資料
* 如果不想使自己糊塗,請不要使用import
* 使用export時,將功能類似的介面組合在一起,並新增合理的注視,這樣你的介面更清晰,別人使用起來更方便
* 不要書寫巢狀太深的程式碼
* 不要書寫太長的module
* 不要書寫太長的函式
* 每行程式碼不能太長
* 避免使用 "_" 匿名變數,請為每個變數選擇有意義的名稱,如夠某個變數暫時不使用,請以下劃線 "_" 開始
* {error, enfile} enfile error in socket 是以為內linux系統中 ulimit 限制, 在root下修改:ulimit -n 25000
* {error, enotconn} 表示socket已經關閉
* 在erlang開發時,慎重使用macro,因為erlang的single assign的緣故,同時呼叫某個marco,而macro又定義了某個變數,可能導致badmatch錯誤。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 = lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log, ?ADDLINEINFO(F), D)).
如果連續使用 WARN, 會出現此錯誤
* erlang中可以定義很多環境變數:
ERL_MAX_ETS_TABLES 設定最大的ets數目 預設1400
ERL_MAX_PORTS erlang最大的port數目 預設1024
* .app檔案中的start_phases, 選項既可以用來作為include applications之間的同步啟動,也可以用來對單個application進行分佈啟動。
順序如下
包含included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go, normal, [])
ok
無included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok
:)
* 確保沒有任何編譯警告
* Erlang中String採用list實現,32位系統中,其1個字元用8個位元組的空間(4個儲存value, 4個儲存指標)。因此string速度較慢,空間佔用較大
* 在Server中,總是盡力書寫尾遞迴(tail-recursive)的函式
* 使用'++'時,left list會被拷貝,然後新增到right list的頭部,因此最好把length較短的list放在左側
* 避免使用regexp,如果需要正規表示式,請使用re
* timer模組的大部分函式實現,依賴於一個process,如果過多使用timer,會導致這個process負載過大,影響效率。
推薦使用erlang:send_after/3及erlang:start_timer/3
* 避免使用list_to_atom/1,因為erlang中atom數量最大為1048576, 且不進行GC控制。因此如果持續性的呼叫list_to_atom/1
可能很容易達到系統上限,從而導致emulator terminate。請使用list_to_existing_atom/1。
* list內部實現為一個列表,因此length(List), 需要遍歷整個list比較耗時
* 對於不同的資料型別,使用不同的size函式:tuple_size/1, byte_size/1, bit_size/1
* 使用binary match來進行binary的分割,而不使用split_binary/2
* 如果兩個list都擁有很多資料,那麼請不要使用'--',而是將資料轉化到ordsets,然後呼叫ordsets:substract/2.
* 對於binary相關操作可以進行binary優化(bin_opt_info編譯選項)程式碼框架:
* f(<<Pattern1,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
f(<<Pattern2,...,Rest/bits>>,...) ->
... % Rest is not used here
f(Rest,...);
...
f(<<>>, ...) ->
ReturnValue.
* 呼叫lists:flatten/1可以將list扁平化,這個操作代價很大,比'++'還要昂貴。下面這些時候我們可以避免:
將資料傳送給port時
呼叫list_bo_binary/1和iolist_to_binary前
* 小的函式可以讓您方便的找出錯誤的函式和程式碼
* 不要在同一行出現相同的符號
20 some_fun() ->
21 L = [{key1, v1}, {key2, [some_record#v21, v22]}],
22 ...
編譯時,會提示line 21 '[' 語法錯誤, 因為21行有多個 '[' ,所以這個bug不能準確定位,你需要花時間去排查程式碼。
好的做法是:
20 some_fun() ->
21 L = [{key1, v1},
22 {key2, [some_record#v21, v22]}
23 ],
...
這樣,編譯其會提示你 line 22 '[' 語法錯誤,你很開就知道是那個地方錯了。
* 使用 CTRL + / 或 init:stop(), 可以退出Erlang, 使用CTRL + G 及 CTRL + C 彈出選單選項,可以選擇是否退出Erlang。
其中CTRL + G可以用來連線其他的shell, CTRL + C可以檢視其他一些系統資訊
Ctrl + C abort 是野蠻的退出方式
* use "open_port({fd,0,2}, [out])" make erlang program write standard error to unix system
* If you don't run experiments before you start designing a new system, your entire system will be an experiment!
* standard data structure desc:
Module Description
sets sets, i.e. a collection of unique elements.
gb_sets sets, but based on a general balanced data structure
gb_tree a general balanced tree
dict maps, also called associative arrays
ets hash tables and ordered sets (trees)
dets on-disk hash tables
Suggestion:
elments count: 0 - 100 | 100 - 10000 | 10000 -
our select : list | ets | gb_tree
* 通過code:clash/0 檢測程式碼中是否有module衝突現象(sticky)
* epmd -d -d 啟動 epmd 可以檢視erlang node之間的通訊
* 將正常的邏輯程式碼和錯誤處理程式碼分離,發生錯誤時,儘管錯誤。由另一個錯誤處理模組進行處理
* 類似於作業系統,我們的程式也可以分為kernel 和 user 兩層, 對於kernel絕對不能出現錯誤, 對於user可以出現錯誤,進行恢復
* process頂層loop涉及的程式碼及函式,最好在一個module中實現
* process 的register name和module名稱一致, 便於尋找程式碼
* 每個process具有一個單一的角色,比如:supervisor 用來進行錯誤恢復, work 工作者,可以出現錯誤, trusted worker 不會出現錯誤
* 通過函式呼叫可以實現的功能,就不要使用sever實現(如gen_server, 及類似的loop 實現)
* 給訊息加一個tag,在發生錯誤的時候,可以定位到訊息,同時也有利於程式的穩健
* 在訊息迴圈中,對於unknown的訊息,請呼叫lib:flush_receive/0 將其清除,減輕process msg queue的長度
* server中總是書寫尾遞迴的迴圈
* 儘量使用record, 而不是原始的tuple來表現資料結構, 在使用record時,使用select match:
#person{name = Name, age = Age} = Person
* 對於返回值,最好也新增一個tag,用來說明返回值型別,或者執行成功與否
* 儘可能少的使用catch和try,在erlang程式中,不推薦主動捕獲異常。只有當我們的邏輯特別複雜,我們可以使用throw來返回資料,使用catch來獲取返回值。
* 當然程式與外界互動,外界資料不可靠時,需要使用catch和try
* 慎重使用process dictory, 當你使用get/1, put/1時,你的應用會具有很大的slide effect。可以通過加入一個新的引數來儲存原本需要儲存到process dictory中資料
* 如果不想使自己糊塗,請不要使用import
* 使用export時,將功能類似的介面組合在一起,並新增合理的注視,這樣你的介面更清晰,別人使用起來更方便
* 不要書寫巢狀太深的程式碼
* 不要書寫太長的module
* 不要書寫太長的函式
* 每行程式碼不能太長
* 避免使用 "_" 匿名變數,請為每個變數選擇有意義的名稱,如夠某個變數暫時不使用,請以下劃線 "_" 開始
* {error, enfile} enfile error in socket 是以為內linux系統中 ulimit 限制, 在root下修改:ulimit -n 25000
* {error, enotconn} 表示socket已經關閉
* 在erlang開發時,慎重使用macro,因為erlang的single assign的緣故,同時呼叫某個marco,而macro又定義了某個變數,可能導致badmatch錯誤。
比如:
-define(ADDLINEINFO1(F),
(
begin
Str1 = lists:concat(["[Mod:", ?MODULE, " Line:", ?LINE, "]"]),
Str1 ++ F
end
)).
-define(WARN(Log, F, D), log4erl:warn(Log, ?ADDLINEINFO(F), D)).
如果連續使用 WARN, 會出現此錯誤
* erlang中可以定義很多環境變數:
ERL_MAX_ETS_TABLES 設定最大的ets數目 預設1400
ERL_MAX_PORTS erlang最大的port數目 預設1024
* .app檔案中的start_phases, 選項既可以用來作為include applications之間的同步啟動,也可以用來對單個application進行分佈啟動。
順序如下
包含included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
=> incl_app_cb:start_phase(go, normal, [])
ok
無included app:
application:start(prim_app)
=> prim_app_cb:start(normal, [])
=> prim_app_cb:start_phase(init, normal, [])
=> prim_app_cb:start_phase(go, normal, [])
ok
* 任何時候,都要重視函式的返回值,通過match確保您的預期,如果發生錯誤,那麼就大膽的表達出來。
轉自:http://blog.csdn.net/zhangxinrun/article/details/6399062
相關文章
- Erlang中的if:讚美與非議
- 30 分鐘學 Erlang (一)
- erlang聊天室
- CentOS 安裝ErlangCentOS
- novaframework/nova:Erlang的開源Web框架。FrameworkWeb框架
- Erlang之父Joe Armstrong去世
- Install erlang to Ubuntu 18.04 LTSUbuntu
- Neo4j/cypher學習筆記與學習建議筆記
- Erlang中的Record詳解
- Erlang vs Elixir by example – kv store
- RabbitMQ和Erlang相容對比MQ
- Java開發基礎知識學習總結之(上)-王者筆記建議收藏Java筆記
- rabbitmq解決erlang版本問題MQ
- Android 開發學習筆記Android筆記
- 學習筆記 - DNS協議筆記DNS協議
- IP協議學習筆記協議筆記
- Raft協議學習筆記Raft協議筆記
- Raft 協議學習筆記Raft協議筆記
- [elixir! #0079] erlang 版本升級 22 -> 24
- Erlang/OTP 24版本釋出
- Erlang這十年 - ferd.ca
- rabbitMQ和對應的erlang版本匹配MQ
- springboot 開發學習筆記1Spring Boot筆記
- 1000行MySQL學習筆記,人手一份,建議收藏!MySql筆記
- OAuth 2.0 協議學習筆記OAuth協議筆記
- Internet安全協議 學習筆記協議筆記
- Erlang Solutions:2022年金融科技報告
- RabbitMQ與Erlang的版本對應關係MQ
- Erlang/Elixir: 用Distillery替換Exam打包器
- 吳恩達機器學習筆記 —— 11 應用機器學習的建議吳恩達機器學習筆記
- ES[7.6.x]學習筆記(十二)高亮 和 搜尋建議筆記
- 2020學習前端開發有前途嗎?(建議收藏)前端
- JS開發步驟學習筆記JS筆記
- NDK學習筆記-NDK開發流程筆記
- Web開發學習筆記——HTTP 概述Web筆記HTTP
- Erlang/Elixir 中的 OTP 程式設計介紹程式設計
- 給Java開發初學者的10個學習建議,助你學習事半功倍!Java
- 給Java開發初學者的10個學習建議,助你學習事半功倍Java
- dubbo學習筆記---dubbo開發實戰筆記