erlang进程的调度效率
一、概述
??? 與大多數(shù)的進(jìn)程相反,Erlang中的并發(fā)很廉價(jià),派生出一個(gè)進(jìn)程就跟面向?qū)ο蟮恼Z言中分配一個(gè)對象的開銷差不多。 在啟動(dòng)一個(gè)復(fù)雜的運(yùn)算時(shí),啟動(dòng)運(yùn)算、派生進(jìn)程以及返回結(jié)果后,所有進(jìn)程神奇的煙消云散,它們的內(nèi)存、郵箱、所持有的數(shù)據(jù)庫句柄、它們打開的套接字,以及一些不樂意手工清理的東西,都一并消失。
? ? Erlang進(jìn)程不是操作系統(tǒng)進(jìn)程,它們由erlang運(yùn)行時(shí)系統(tǒng)實(shí)現(xiàn),比線程要輕量的多,單個(gè)erlang系統(tǒng)可以輕易地派生出成百上千個(gè)進(jìn)程。運(yùn)行時(shí)系統(tǒng)中所有的進(jìn)程都是隔離的,單個(gè)進(jìn)程的內(nèi)存不與其他進(jìn)程共享,也不會(huì)被瀕死或跑瘋的進(jìn)程破壞。
? ? 在操作系統(tǒng)中,典型的線程會(huì)在地址空間中為自己預(yù)留數(shù)兆的棧空間(也就是說32位的機(jī)器上并發(fā)線程最多也就幾千個(gè)),棧空間溢出便會(huì)導(dǎo)致崩潰。erlang進(jìn)程在啟動(dòng)時(shí)棧空間只有幾百個(gè)字節(jié),并會(huì)按需伸縮。
二、示例
1 14> Pid = spawn(fun() -> timer:sleep(60000), primes:primelist(100000) end). %% 派生一個(gè)進(jìn)程,等待1分鐘后做素?cái)?shù)運(yùn)算。 素?cái)?shù)功能代碼已提前編寫好。 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}, %%剛啟動(dòng)的erlang進(jìn)程所占的堆的大小僅為233字節(jié),棧的大小10個(gè)字節(jié)。 17 {stack_size,10}, 18 {reductions,43}, %%創(chuàng)建erlang進(jìn)程僅消耗了43個(gè)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). %% 進(jìn)程處于掛起狀態(tài),堆、棧、時(shí)間片消耗都不會(huì)變 25 0 26 22> erlang:statistics(run_queue). %% 進(jìn)程進(jìn)入運(yùn)行隊(duì)列,準(zhǔn)備被調(diào)度。 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}, %%進(jìn)程在做素?cái)?shù)計(jì)算, 堆棧大小隨著需要開始增加。 消耗的時(shí)間片也會(huì)隨著計(jì)算量增加而增加。 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}, %% 隨著計(jì)算的結(jié)束, 棧空間開始收縮, 這里可以看到堆空間沒有變,堆的分配是由erlang GC來控制的, 進(jìn)程結(jié)束時(shí)由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,[]}]三、進(jìn)程的調(diào)度
? ? 由于Erlang虛擬機(jī)對SMP的支持,每個(gè)操作系統(tǒng)線程都可以運(yùn)行在一個(gè)調(diào)度器上,每個(gè)調(diào)度器擁有一自己的運(yùn)行隊(duì)列,這樣避免了多個(gè)調(diào)度器同時(shí)調(diào)度在運(yùn)行隊(duì)列中的任務(wù)產(chǎn)生的沖突,但是如何保證調(diào)度隊(duì)列任務(wù)分配的公平性,Erlang引入了一個(gè)高效和公平的概念,遷移邏輯。遷移邏輯利用在系統(tǒng)中收集的統(tǒng)計(jì)數(shù)據(jù),控制和平衡了隊(duì)列。
? ? Erlang啟動(dòng)模擬器的時(shí)候可以加上+S去指定最大調(diào)度器數(shù)和可用調(diào)度器數(shù)。可用調(diào)度器數(shù)可以在模擬器運(yùn)行時(shí)更改。
-> 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下面我們嘗試起多個(gè)erlang進(jìn)程去做素?cái)?shù)運(yùn)算,然后看看調(diào)度隊(duì)列情況。
-> erl +S 8:8 %%啟動(dòng)8個(gè)調(diào)度器同時(shí)可用。 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). %%之前沒有任務(wù)進(jìn)入調(diào)度隊(duì)列 0 2> [spawn(fun() -> timer:sleep(5000), primes:primelist(10000) end) || _ <- lists:seq(1, 10)]. %% 同時(shí)啟動(dòng)10個(gè)進(jìn)程做素?cái)?shù)運(yùn)算 [<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). %%同時(shí)有7個(gè)進(jìn)程被調(diào)度運(yùn)行,3個(gè)進(jìn)程出去準(zhǔn)備狀態(tài) 3 7> erlang:statistics(run_queue). %%兩個(gè)任務(wù)被換入。 1 8> erlang:statistics(run_queue). %%任務(wù)執(zhí)行完畢,沒有任務(wù)處于等待狀態(tài)。 0那么問題來了,在同樣的硬件環(huán)境下,是不是調(diào)度器越多,進(jìn)程處理的速度越快呢?列出測試結(jié)果:
-> erl +S 4:4 %%%啟動(dòng)4個(gè)可用調(diào)度器 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 %%%啟動(dòng)8個(gè)可用調(diào)度器 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從測試結(jié)果看,并不是調(diào)度器越多越好,也不是越少越好,合適實(shí)際應(yīng)用場景才是最好的。
轉(zhuǎn)載于:https://www.cnblogs.com/liquan2005/p/8870011.html
總結(jié)
以上是生活随笔為你收集整理的erlang进程的调度效率的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 八年级英语57页答案
- 下一篇: 6264:走出迷宫(DFS和BFS)