erlang进程的调度效率
一、概述
??? 與大多數的進程相反,Erlang中的并發很廉價,派生出一個進程就跟面向對象的語言中分配一個對象的開銷差不多。 在啟動一個復雜的運算時,啟動運算、派生進程以及返回結果后,所有進程神奇的煙消云散,它們的內存、郵箱、所持有的數據庫句柄、它們打開的套接字,以及一些不樂意手工清理的東西,都一并消失。
? ? Erlang進程不是操作系統進程,它們由erlang運行時系統實現,比線程要輕量的多,單個erlang系統可以輕易地派生出成百上千個進程。運行時系統中所有的進程都是隔離的,單個進程的內存不與其他進程共享,也不會被瀕死或跑瘋的進程破壞。
? ? 在操作系統中,典型的線程會在地址空間中為自己預留數兆的棧空間(也就是說32位的機器上并發線程最多也就幾千個),棧空間溢出便會導致崩潰。erlang進程在啟動時棧空間只有幾百個字節,并會按需伸縮。
二、示例
1 14> Pid = spawn(fun() -> timer:sleep(60000), primes:primelist(100000) end). %% 派生一個進程,等待1分鐘后做素數運算。 素數功能代碼已提前編寫好。 2 <0.55.0> 3 15> erlang:process_info(Pid). 4 [{current_function,{timer,sleep,1}}, 5 {initial_call,{erlang,apply,2}}, 6 {status,waiting}, 7 {message_queue_len,0}, 8 {messages,[]}, 9 {links,[]}, 10 {dictionary,[]}, 11 {trap_exit,false}, 12 {error_handler,error_handler}, 13 {priority,normal}, 14 {group_leader,<0.26.0>}, 15 {total_heap_size,233}, 16 {heap_size,233}, %%剛啟動的erlang進程所占的堆的大小僅為233字節,棧的大小10個字節。 17 {stack_size,10}, 18 {reductions,43}, %%創建erlang進程僅消耗了43個reductions, 可見erlang的輕量。 19 {garbage_collection,[{min_bin_vheap_size,46422}, 20 {min_heap_size,233}, 21 {fullsweep_after,65535}, 22 {minor_gcs,0}]}, 23 {suspending,[]}] 24 17> erlang:statistics(run_queue). %% 進程處于掛起狀態,堆、棧、時間片消耗都不會變 25 0 26 22> erlang:statistics(run_queue). %% 進程進入運行隊列,準備被調度。 27 1 28 23> erlang:process_info(Pid). 29 [{current_function,{primes,'-primelist/3-lc$^0/1-0-',2}}, 30 {initial_call,{erlang,apply,2}}, 31 {status,runnable}, 32 {message_queue_len,0}, 33 {messages,[]}, 34 {links,[]}, 35 {dictionary,[]}, 36 {trap_exit,false}, 37 {error_handler,error_handler}, 38 {priority,normal}, 39 {group_leader,<0.26.0>}, 40 {total_heap_size,393300}, 41 {heap_size,75113}, %%進程在做素數計算, 堆棧大小隨著需要開始增加。 消耗的時間片也會隨著計算量增加而增加。 42 {stack_size,13773}, 43 {reductions,89874499}, 44 {garbage_collection,[{min_bin_vheap_size,46422}, 45 {min_heap_size,233}, 46 {fullsweep_after,65535}, 47 {minor_gcs,3085}]}, 48 {suspending,[]}] 49 27> erlang:statistics(run_queue). 50 0 51 29> erlang:process_info(Pid). 52 [{current_function,{primes,'-primelist/3-lc$^0/1-0-',2}}, 53 {initial_call,{erlang,apply,2}}, 54 {status,runnable}, 55 {message_queue_len,0}, 56 {messages,[]}, 57 {links,[]}, 58 {dictionary,[]}, 59 {trap_exit,false}, 60 {error_handler,error_handler}, 61 {priority,normal}, 62 {group_leader,<0.26.0>}, 63 {total_heap_size,393300}, 64 {heap_size,75113}, 65 {stack_size,87}, %% 隨著計算的結束, 棧空間開始收縮, 這里可以看到堆空間沒有變,堆的分配是由erlang GC來控制的, 進程結束時由GC來回收。 66 {reductions,958602600}, 67 {garbage_collection,[{min_bin_vheap_size,46422}, 68 {min_heap_size,233}, 69 {fullsweep_after,65535}, 70 {minor_gcs,33117}]}, 71 {suspending,[]}]三、進程的調度
? ? 由于Erlang虛擬機對SMP的支持,每個操作系統線程都可以運行在一個調度器上,每個調度器擁有一自己的運行隊列,這樣避免了多個調度器同時調度在運行隊列中的任務產生的沖突,但是如何保證調度隊列任務分配的公平性,Erlang引入了一個高效和公平的概念,遷移邏輯。遷移邏輯利用在系統中收集的統計數據,控制和平衡了隊列。
? ? Erlang啟動模擬器的時候可以加上+S去指定最大調度器數和可用調度器數。可用調度器數可以在模擬器運行時更改。
-> erl +S 16:8 Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:16:8] [async-threads:10] [hipe] [kernel-poll:false]Eshell V5.10.4 (abort with ^G) 1> erlang:system_info(schedulers_online). 8 2> erlang:system_info(schedulers). 16下面我們嘗試起多個erlang進程去做素數運算,然后看看調度隊列情況。
-> erl +S 8:8 %%啟動8個調度器同時可用。 Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]Eshell V5.10.4 (abort with ^G) 1> erlang:statistics(run_queue). %%之前沒有任務進入調度隊列 0 2> [spawn(fun() -> timer:sleep(5000), primes:primelist(10000) end) || _ <- lists:seq(1, 10)]. %% 同時啟動10個進程做素數運算 [<0.36.0>,<0.37.0>,<0.38.0>,<0.39.0>,<0.40.0>,<0.41.0>,<0.42.0>,<0.43.0>,<0.44.0>,<0.45.0>] 5> erlang:statistics(run_queue). %%同時有7個進程被調度運行,3個進程出去準備狀態 3 7> erlang:statistics(run_queue). %%兩個任務被換入。 1 8> erlang:statistics(run_queue). %%任務執行完畢,沒有任務處于等待狀態。 0那么問題來了,在同樣的硬件環境下,是不是調度器越多,進程處理的速度越快呢?列出測試結果:
-> erl +S 4:4 %%%啟動4個可用調度器 Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] 2> [spawn(fun() -> {P1, _P2} = timer:tc(primes, primelist, [100000]), io:format("timer:~p~n", [P1]) end) || _ <- lists:seq(1, 10)]. timer:185078651 timer:190735178 timer:192956743 timer:193186850 timer:220074562 timer:222929652 timer:234756209 timer:235304593 timer:235474721 timer:236500425-> erl +S 8:8 %%%啟動8個可用調度器 Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]Eshell V5.10.4 (abort with ^G) 1> 1> 1> 1> [spawn(fun() -> {P1, _P2} = timer:tc(primes, primelist, [100000]), io:format("timer:~p~n", [P1]) end) || _ <- lists:seq(1, 10)]. [<0.35.0>,<0.36.0>,<0.37.0>,<0.38.0>,<0.39.0>,<0.40.0>,<0.41.0>,<0.42.0>,<0.43.0>,<0.44.0>] timer:187405676 timer:187568120 timer:188255698 timer:188577806 timer:190819642 timer:191208176 timer:235470698 timer:236842370 timer:237630863 timer:238206383-> erl +S 16:11 Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:16:11] [async-threads:10] [hipe] [kernel-poll:false]Eshell V5.10.4 (abort with ^G) 1> [spawn(fun() -> {P1, _P2} = timer:tc(primes, primelist, [100000]), io:format("timer:~p~n", [P1]) end) || _ <- lists:seq(1, 10)]. [<0.35.0>,<0.36.0>,<0.37.0>,<0.38.0>,<0.39.0>,<0.40.0>,<0.41.0>,<0.42.0>,<0.43.0>,<0.44.0>]timer:243000833 timer:243636514 timer:244753411 timer:245005027 timer:245296405 timer:245356679 timer:245659526 timer:245662159 timer:245731926 timer:245779971從測試結果看,并不是調度器越多越好,也不是越少越好,合適實際應用場景才是最好的。
轉載于:https://www.cnblogs.com/liquan2005/p/8870011.html
總結
以上是生活随笔為你收集整理的erlang进程的调度效率的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 八年级英语57页答案
- 下一篇: 6264:走出迷宫(DFS和BFS)