1. 程式人生 > >Erlang一些好的程式設計習慣

Erlang一些好的程式設計習慣

前言

學習Erlang的時候在書的留白處隨手記錄了一些東西,還有一些記錄在了demo的註釋裡面,今天抽時間整理出來了一部分,分享一下.

正文

  1. Erlang的設計哲學是為每一個獨立的事件建立一個新程序.
  2. Erlang的容錯處理:如果不能完成一個任務就死掉 讓其它正常的程序來善後。link函式就是用來建立這種程序間的雙向連線來監測非正常退出,並做出處理。
  3. BIFs是built-in functions的縮寫代表這些方法是Erlang執行時系統的一部分
  4. side-effect-free無副作用,其中一種定義是說:一個程式執行前後保持程式的狀態不變,不改變非區域性變數的值,不改變傳入引數值,也無I/O
  5. 寫測試模組的時候不必頻繁匯出函式  –compile(export_all) 就可以匯出所有函式
  6. Erlang中整數值沒有上限值,最大值只是受限於硬體(記憶體有多大)
  7. 在Erlang Shell中可以方便的做進位制轉換:Base#Value Base的範圍2~16 2#101011
  8. Erlang Shell中查詢ASCII碼 $1 $a $A $\n $\}
  9. Erlang Shell中釋放變數使用f() 定義record使用rd(),讀取shell輸入使用io:read/1可以接受輸入Erlang term.
  10. Erlang Shell中接受訊息使用flush() 自己的Pid是self() 檢視程序資訊使用processes() i() 但是不要在程序非常多的場景使用,會消耗大量記憶體
  11. atom是否已經註冊的:registered() unregister(Pid) whereis(Atom) regs().
  12. atom能夠進行的唯一運算就是比較
  13. atom是可以使用.和@的,但是別給自己添亂
  14. atom會被記錄在ERT系統表中,只需要幾個位元組,atom之間比較起來也很快
  15. atom不參與Erlang GC,所以atom不能無節制的建立,list_to_existing_atom可以一定程度上緩解建立重複atom的記憶體消耗
  16. Tuple是Erlang表達複雜資料結構的手段,第一個元素經常被稱作Tag,Tag Massage是Erlang程式設計的最佳實踐
  17. Tuple索引是從1開始的,執行一下 element(1,{a,b,c}).看看 再試一下element(0,{a,b,c})看看報什麼錯
  18. Tuple大小使用tuple_size({1,2,3,4,5}).
  19. M++N會遍歷列表M所以如果必須要使用++也要讓資料量小的List在前面
  20. proplist對於處理key_value的list真的是非常方面
  21. List=[Element|List]所以你可以在shell中可以輸入[1,2|3],嘗試匹配一下它 [A,B,C]=[1,2|3]再試一下[P,Q]=[1,2,3]
  22. List最後一個元素是空列表[],被稱作well-formed list正則列表,[1,2|3]這種結構要避免
  23. –操作符是針對元素進行的 [1,2]–[3]結果是[1,2] [2,2]–[2]結果是[2],運算順序是從右到左, [1,2,3]–[1,2]–[1].結果是[1,3]
  24. number<atom<reference<fun<port<pid<tuple<list<binary 之所以有這樣一個比較關係,就是為了支援泛型比較
  25. =:= =/=精確比較運算不僅比較值,還比較型別,效率更高
  26. Erlang GC的特點是:每個程序獨立進行GC ,分代(generational garbage) ,複製回收
  27. Erlang的模式匹配作用:1.變數賦值 2.提取變數值 3.控制流
  28. 寫function的時候在最後新增一個catch_all的方法也被認為是最佳實踐
  29. 如果可預見結果集的所有可能性,那麼case語句不建議使用catch_all
  30. if語句會對Guard子句做catch,所以 if 1/0 ->a; true ->b end.的返回值是b而不是丟擲異常
  31. if的Guard子句放在變數裡就可以讓異常丟擲來:G=1/0 , if G->a; true ->b end.
  32. Guard subexpressions resulting in a runtime error are treated as returning false.
  33. Guard可以使用, ; 表達多個條件if  X=:=1,Y<2;X+Y<4 ->ok; true ->error end.
  34. process dictionary幾乎被描述成洪水猛獸了,對於一次寫入然後就只讀的配置性資料放在程序字典應該沒有問題
  35. Erlang出錯法則:讓錯誤報告在它發生的地方
  36. 檢視module的元資料資訊  比如a.erl a:module_info().   m(a).
  37. Erlang的超程式設計Meta Programming確實直接,apply/3 甚至在引數確定情況下的直接呼叫M:F(A)
  38. Concurrency is the ability for different functions to execute in parallel without affecting each other unless explicitly programmed to do so.
  39. 我們要遍歷ETS可以使用first/next 也可以使用foldr foldl,但是後者會把ETS資料複製到程序,資料量大時有效率問題
  40. 負責程序建立職責的是Erlang VM中的Scheduler
  41. spawn第三個引數是List,這個呼叫的時候注意!!
  42. Spawning a process will never fail!!!
  43. Sending a message will never fail!!!
  44. receive子句的處理邏輯抽取為一個獨立的方法是推薦的做法
  45. receive如果接受到沒有匹配任何子句的訊息,那麼這條訊息就會儲存在mailbox,長此以往就會耗盡記憶體系統崩潰之險;
  46. 訊息傳送的速度快於程序處理的速度就會增加CPU上的消耗,因為會反覆掃描mailbox
  47. Not handling unknown messages should therefore be treated as a bug. 匹配未知訊息會導致難以發現錯誤,所以這些位置要記錄日誌
  48. 選擇性接受和mailbox這兩個東西就解決了訊息接受緩衝區的問題
  49. A race condition occurs when the behavior of a system depends on the order in which certain events occur: these events “race” to influence the behavior.
  50. 上面兩個不失敗的設計原則是為了解除程序依賴:另外一個程序的建立和接受訊息是否成功不影響當前程序的正常執行
  51. timer:tc/3計算方法的執行時間 這個構建簡單的效能測試很方便
  52.  {‘EXIT’, Pid, Reason}退出訊息的格式包含的資訊:誰因為什麼退出了
  53.  process_flag(trap_exit, true).退出截獲的決策當然是在生命週期的早期進行配置。所以一般出現在init階段。
  54. 截獲到底做了一件什麼事情呢?把退出訊息放在程序收件箱中當成一個普通的訊息來處理。這就相當於我們把異常資訊放在返回結果中的情況
  55. receive接收並處理退出訊號,退出訊息被截獲就不再傳播
  56. link是雙向的,monitor是單向的,被監控的程序死掉後,監控程序會收到  {‘DOWN’,Reference,process,Pid,Reason} 訊息
  57. 如果接收到{‘EXIT’, Pid, Reason}的程序沒有trap_exit,而且Reason不是normal,這個程序就會終止掉並繼續傳播這個退出訊息
  58. 所有的BIFs的執行都是原子性的,所以spawn_link不等同於spawn 和 link的組合呼叫
  59. {‘EXIT’, Pid, Reason}Reason如果是kill,關聯程序無論是否trap_exit都會死掉
  60. {‘EXIT’, Pid, Reason}Reason如果是normal,關聯程序trap_exit會收到一條{‘EXIT’, Pid, normal}訊息,如果沒有trap_exit什麼都不會發生
  61.  可以使用record_info()來檢視record定義
  62. ETS也是不參與GC的
  63. Erlang是動態強型別的語言 dynamic-strong Typing
  64. windows環境Erlang GUI工具:toolbar:start(). tv:start() pman:start(). appmon:start() debugger:start()
  65. 還有一個WebUI的工具 webtool:start().
  66. Note:  Using the form  [1 | 2]  gives what we call an ‘improper list’. Improper lists will work when you pattern match in the  [Head|Tail]  manner, but will fail to be used with standard functions of Erlang (even  length() ). This is because Erlang expects proper lists.  Proper lists end with an empty list as their last cell . When declaring an item like [2] , the list is automatically formed in a proper manner. As such,  [1|[2]]  would work! Improper lists, although syntactically valid, are of very limited use outside of user-defined data structures.
  67. 在EShell中執行Erlang方法 
    $> erl -boot start_clean -noshell -eval ‘io:format(“hi\n”)’ -eval ‘halt(0)’ 
    % or 
    $> erl -boot start_clean -noshell -eval ‘io:format(“hi\n”), halt(0)’

    % example: 
    erl -sname ad_service -eval ‘ok=mnesia:create_schema([node()]).’ -s init stop

  68. 列印浮點型 
    lists:flatten(io_lib:format(“~.*..f”, [2, S]));

    3> lists:flatten(io_lib:format(“~.*..f”, [2, 192.2225])). 
    “192.22″ 
    4> lists:flatten(io_lib:format(“~.*..f”, [3, 192.2225])). 
    “192.223″

    5> lists:flatten([io_lib:format("~8.2.0B,", [L]) || L <- [1,2,3]]). 
    “00000001,00000010,00000011,” 
    6> lists:flatten([io_lib:format("~2.16.0B ", [L]) || L <- [1,2,3]]). 
    “01 02 03 “.

  69. 找出消耗記憶體最多的程序 
    lists:reverse(lists:keysort(2,[{P, erlang:process_info(P, heap_size)} || P <- erlang:processes()])).
  70. 找到最消耗記憶體的ETS表 
    lists:reverse(lists:keysort(2,[{T, ets:info(T, memory)} || T <- ets:all()])).
  71. record型別作為引數的小技巧 
    -record(x,{name,zz}). 
    -record(y,{yy,name}). 
    -export([test1/0,test2/0]). 
    -define(create(Type,Name),#Type{name = Name}).

    test1() -> ?create(x,”Noel”). % -> {x,”Noel”,undefined} 
    test2() -> ?create(y,”Noel”). % -> {y,undefined,”Noel”}

  72. binary_to_list VS bitstring_to_list

    1> A = <<1:2, 23:6>>. 
    <<”W”>> 
    2> B = <<1:2, 23:5>>. 
    <<55:7>> 
    3> binary_to_list(A). 
    “W” 
    4> binary_to_list(B). 
    ** exception error: bad argument 
    in function binary_to_list/1 
    called as binary_to_list(<<55:7>>) 
    5> bitstring_to_list(A). 
    “W” 
    6> bitstring_to_list(B). 
    [<<55:7>>]

  73. Erlang執行作業系統命令 os:cmd(“uptime”).
  74. [3] or “3″ 
    17> [51] =:= “3″. 
    true 
    18> [3] =:= “3″. 
    false 
    19>
  75.  

    如果僅僅是將一系列的模組打包在一起,並不需要啟動application,那麼只需要在app檔案中移除掉{mod,{Module,Args}}配置節即可.這種Libiary Application典型範例就是stdlib. 
    看配置檔案:

    {application, stdlib,
     [{description, "ERTS  CXC 138 10"},
      {vsn, "1.18"},
      {modules, [array,
             base64,
             beam_lib,
             binary,
             c,
             calendar,
             dets,
                 dets_server,
             dets_sup,
             dets_utils,
             dets_v8,
             dets_v9,
             dict,
             digraph,
             digraph_utils,
             edlin,
             edlin_expand,
             epp,
             eval_bits,
             erl_bits,
             erl_compile,
             erl_eval,
                 erl_expand_records,
             erl_internal,
             erl_lint,
             erl_parse,
             erl_posix_msg,
             erl_pp,
             erl_scan,
             erl_tar,
             error_logger_file_h,
             error_logger_tty_h,
             escript,
             ets,
             file_sorter,
             filelib,
             filename,
             gb_trees,
             gb_sets,
             gen,
             gen_event,
             gen_fsm,
             gen_server,
             io,
             io_lib,
             io_lib_format,
             io_lib_fread,
             io_lib_pretty,
             lib,
             lists,
             log_mf_h,
             math,
             ms_transform,
             orddict,
             ordsets,
             otp_internal,
             pg,
             pool,
             proc_lib,
             proplists,
                 qlc,
                 qlc_pt,
             queue,
             random,
             re,
             sets,
             shell,
             shell_default,
             slave,
             sofs,
             string,
             supervisor,
             supervisor_bridge,
             sys,
             timer,
             unicode,
             win32reg,
             zip]},
      {registered,[timer_server,rsh_starter,take_over_monitor,pool_master,
                   dets]},
      {applications, [kernel]},
      {env, []}]}.
  76.  erlang:now常用作隨機數的種子,這個並不是太好,建議使用:
    4> <<A:32,B:32,C:32>> = crypto:strong_rand_bytes(12) .
    <<42,136,117,238,28,89,154,241,88,189,70,139>>
    5> b().
    A = 713586158
    B = 475634417
    C = 1488799371
    ok

併發&並行    concurrency  and  parallelism .

In many places both words refer to the same concept. They are often used as two different ideas in the context of Erlang. For many Erlangers, concurrency refers to the idea of having many actors running independently, but not necessarily all at the same time. Parallelism is having actors running exactly at the same time. I will say that there doesn’t seem to be any consensus on such definitions around various areas of computer science, but I will use them in this manner in this text. Don’t be surprised if other sources or people use the same terms to mean different things.

This is to say Erlang had concurrency from the beginning, even when everything was done on a single core processor in the ’80s. Each Erlang process would have its own slice of time to run, much like desktop applications did before multi-core systems.

Parallelism was still possible back then; all you needed to do was to have a second computer running the code and communicating with the first one. Even then, only two actors could be run in parallel in this setup. Nowadays, multi-core systems allows for parallelism on a single computer (with some industrial chips having many dozens of cores) and Erlang takes full advantage of this possibility.

The distinction between concurrency and parallelism is important to make, because many programmers hold the belief that Erlang was ready for multi-core computers years before it actually was. Erlang was only adapted to true  symmetric multiprocessing  in the mid 2000s and only got most of the implementation right with the R13B release of the language in 2009. Before that,  SMP  often had to be disabled to avoid performance losses. To get parallelism on a multicore computer without SMP, you’d start many instances of the VM instead.

An interesting fact is that because Erlang concurrency is all about isolated processes, it took no conceptual change at the language level to bring true parallelism to the language. All the changes were transparently done in the VM, away from the eyes of the programmers.

Erlang Type

Through the years, there were some attempts to build type systems on top of Erlang. One such attempt happened back in 1997, conducted by Simon Marlow, one of the lead developers of the Glasgow Haskell Compiler, and Philip Wadler, who worked on Haskell’s design and has contributed to the theory behind monads ( Read the paper  on said type system). Joe Armstrong later commented on the paper :

One day Phil phoned me up and announced that a) Erlang needed a type system, b) he had written a small prototype of a type system and c) he had a one year’s sabbatical and was going to write a type system for Erlang and “were we interested?” Answer —“Yes.”

Phil Wadler and Simon Marlow worked on a type system for over a year and the results were published in [20]. The results of the project were somewhat disappointing. To start with, only a subset of the language was type-checkable, the major omission being the lack of process types and of type checking inter-process messages.

二進位制列表解析

%%The only change in syntax from regular list comprehensions is the <- which became <= and using binaries (<<>>) instead of lists ([]). 

1> Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>.
<<213,45,132,64,76,32,76,0,0,234,32,15>>
2> RGB = [ {R,G,B} || <<R:8,G:8,B:8>> <= Pixels ].
[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]
3> << <<R:8, G:8, B:8>> ||  {R,G,B} <- RGB >>.
<<213,45,132,64,76,32,76,0,0,234,32,15>>
4> << <<R:8, G:8, B:8>> ||  {R,G,B} <- RGB >>.
<<213,45,132,64,76,32,76,0,0,234,32,15>>
5> << <<Bin>> || Bin <- [<<3,7,5,4,7>>] >>.
** exception error: bad argument
6> << <<Bin/binary>> || Bin <- [<<3,7,5,4,7>>] >>.
<<3,7,5,4,7>>
7> << <<(X+1)/integer>> || <<X>> <= <<3,7,5,4,7>> >>.
<<4,8,6,5,8>>

Note: At the time of this writing, binary comprehensions were seldom used and not documented very well. As such, it was decided not to dig more than what is necessary to identify them and understand their basic working. To understand more bit syntax as a whole, read the  white paper defining their specification .

注:原文出處(http://www.erlang-cn.com/716.html)