對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(<< attern1,...,Rest/bits>>,...) ->  
       ... % Rest is not used here  
       f(Rest,...);  
    f(<< attern2,...,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
相關文章
相關標籤/搜索