erlang:调度程序开销正在运行的进程

时间:2015-07-07 00:44:16

标签: erlang

这是一个简单的程序,我的机器有两个CPU核心。 我希望当我生成两个进程时,消耗时间与我只生成一个进程的时间相同。

-module(test).
-export([main/1]).
forRange(Begin,End,Total) when Begin < End ->
  forRange(Begin+1,End,Total+Begin);
forRange(_,_,Total)->
  io:format("~p ~n", [Total]),
  ok.
main([A, B])->
  process_flag(trap_exit, true),
  Pids = [spawn_link(fun() -> forRange(1,list_to_integer(A),0) end) || _ <- lists:seq(1, list_to_integer(B))],
  [ receive
    {'EXIT', Pid, normal} ->
      ok
  end || Pid <- Pids ].

测试结果是:

$ time escript test.beam 1000000000 1
499999999500000000 

real    0m3.895s
user    0m3.820s
sys 0m0.068s
$ time escript test.beam 1000000000 2
499999999500000000 
499999999500000000 

real    0m4.582s
user    0m8.788s
sys 0m0.168s

但是,结果表明,当我生成两个进程时,实际时间比一个进程的情况要大,这意味着Erlang调度程序有一些开销?但是对于这个简单的例子,这些过程应该完全并行运行。

2 个答案:

答案 0 :(得分:3)

我已经为编译模块修改了一点代码。

-module(test).
-export([test/2]).

forRange(Begin,End,Total) when Begin < End ->
    forRange(Begin+1,End,Total+Begin);
forRange(_,_,Total)->
    io:format("~p ~n", [Total]),
    ok.

test(A, B)->
    Flag = process_flag(trap_exit, true),
    Pids = [spawn_link(fun() -> forRange(1,A,0) end) || _ <- lists:seq(1, B)],
    [ receive
          {'EXIT', Pid, normal} ->
              ok
      end || Pid <- Pids ],
    process_flag(trap_exit, Flag).

然后我编译并运行。

$ erlc test.erl
$ erl -tbt
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V7.0  (abort with ^G)
1> timer:tc(fun() -> test:test(500000000,1) end).
124999999750000000 
{8218153,true}
2> timer:tc(fun() -> test:test(500000000,1) end).
124999999750000000 
{8292624,true}
3> timer:tc(fun() -> test:test(500000000,2) end).
124999999750000000 
124999999750000000 
{9119394,true}
4> timer:tc(fun() -> test:test(500000000,2) end).
124999999750000000 
124999999750000000 
{9116651,true}
5> (9116651+9119394)/(8218153+8292624).
1.10449344691652

正如你所看到的,我故意做了两件事。首先,我将调度程序锁定到CPU内核,然后我选择重复次数来运行它更长,几乎是10s。目的是使其更具可预测性,为调度员提供更多时间来安排工作,并使测量更加稳定。正如你所看到的,差异现在只有10%。我有现代CPU(型号名称:Intel(R)Core(TM)i5 CPU M 520 @ 2.40GHz),如果只使用一个CPU核心,我可以自动超频,我倾向于将这种差异归咎于此。

如果您希望查看调度程序开销,则应尝试更多进程:

1> timer:tc(fun() -> test:test(100000000,16) end).
4999999950000000 
...
4999999950000000 
{13466677,true}
2> timer:tc(fun() -> test:test(100000000,16) end).
...
{13625811,true}
3> timer:tc(fun() -> test:test(100000000,32) end).
...
{27325526,true}
4> timer:tc(fun() -> test:test(100000000,32) end).
...
{27461209,true}
5> (27325526+27461209)/(13466677+13625811)/2.
1.0111056430107122

现在这1.1%你可能可以归咎于schdeulers开销。

答案 1 :(得分:0)

在&#39; 2&#39;例如,您创建的流程数量是原来的两倍 由于进行产卵的过程是单线程的,因此需要更长的时间来产生两倍的产卵。 一个更好的方式来展示我认为你想要展示的内容将是产生B流程,每个流程都会产生一个流程。这样,实际的产卵也是并行完成的。