Erlang在多核CPU上

时间:2011-08-10 04:03:41

标签: erlang parallel-processing

我正在学习erlang,并且对于并行化工作是多么容易印象深刻。为了练习,我挖出了良好的纤维Fibanocci序列。在下面的代码中,我尝试通过一次计算三个昂贵的产品来利用并行化。

-module (fib4).
-export ( [main/1] ).

main (N) ->
    fib (list_to_integer (atom_to_list (hd (N) ) ) ),
    halt (0).

path (1, Acc) -> Acc;
path (N, Acc) when N rem 2 =:= 0 ->
    path (N - 1, [step | Acc] );
path (N, Acc) ->
    path ( (N - 1) div 2, [jump | Acc] ).

fib (N) -> fib (1, 1, path (N, [] ) ).

fib (N, Nplus1, [Last] ) ->
    case Last of
        step -> Nplus1;
        jump -> N * N + Nplus1 * Nplus1
    end;

fib (N, Nplus1, [jump | T] ) ->
    Pid = self (),
    spawn (fun () -> Pid ! {n1sq, Nplus1 * Nplus1} end),
    spawn (fun () -> Pid ! {mul, 2 * N * Nplus1} end),
    spawn (fun () -> Pid ! {nsq, N * N} end),
    {Nsq, N1sq, Mul} = loop (0, 0, 0),
    fib (Nsq + N1sq, N1sq + Mul, T);

fib (N, Nplus1, [step | T] ) ->
    fib (Nplus1, N + Nplus1, T).

loop (Nsq, N1sq, Mul) ->
    receive
        {nsq, Val} ->
            if
                N1sq > 0 andalso Mul > 0 -> {Val, N1sq, Mul};
                true -> loop (Val, N1sq, Mul)
            end;
        {n1sq, Val} ->
            if
                Mul > 0 andalso Nsq > 0 -> {Nsq, Val, Mul};
                true -> loop (Nsq, Val, Mul)
            end;
        {mul, Val} ->
            if
                N1sq > 0 andalso Nsq > 0 -> {Nsq, N1sq, Val};
                true -> loop (Nsq, N1sq, Val)
            end
    end.

我在Phenom X4上运行此代码,并且在我的机器计算fib(10000000)的那一刻,只有一到两个核心正在工作而其他核心正在闲置。

enter image description here

我的问题是:

  • 谁决定工作线程分配了多少个核心? erlang节点或我的操作系统(在我的情况下是ubuntu 2.6.38)?
  • 由于两个或三个磁芯空转,我是否会放慢速度?

3 个答案:

答案 0 :(得分:15)

Erlang的默认行为历来是运行一个调度程序,它基本上是一个本机OS线程,它选择从队列运行Erlang任务。随着多核和多处理器系统的出现,运行时得到了扩展以利用。使用-smp enabled启动运行时将导致运行时创建多个调度程序,通常每个逻辑CPU一个。您可以使用-S标记手动指定调度程序的数量,例如-S 16

Erlang Run-Time System Reference Manual中记录了这一点。

可以在this discussion thread中找到有关SMP支持的更深入讨论。

修改

我还应该指出,从R12B开始,SMP默认在支持它的平台上启用(相当于-smp auto标志)。如果您对自己的运行时很好奇,那么讨论主题中的以下引用将会引起关注:

  

你可以看到从第一行打印输出中选择的内容   “erl”命令。例如。   Erlang(BEAM)模拟器版本5.6.4 [源代码] [smp:4] [asynch-threads:0] .....

     

上面的“[smp:4]”告诉SMP VM运行并有4个调度程序。

答案 1 :(得分:9)

你看到这么少的并行性的原因是你的程序基本上是顺序的。所有工作都在fib / 3功能的一个过程中完成。您生成的进程只发送一条消息然后死亡,并且产生进程同步等待这些消息,因此没有真正的并发。您也可以直接用这些值调用loop / 3函数。

否则就像其他人提到的那样,Erlang会自动使用所有可用的多个内核,并在可能的情况下分配这些内核。但是在你的情况下,几乎不需要这样做,也没有增益,因此系统不会这样做。

这实际上是编写并发应用程序中比较困难的事情之一。将事物分散到许多进程中是不够的,实际上必须确保这些进程实际并发运行。这意味着重新考虑您的算法,这可能很困难。

答案 2 :(得分:6)

Erlang不使用传统意义上的线程。 Erlang VM为CPU的每个硬件核心创建一个系统线程。当你在Erlang中启动一个线程时,你实际上是在创建一个“任务”,它与系统线程不同。 Erlang在VM内部管理这些任务。

根据VM及其配置,这些任务可能会也可能不会映射到各个CPU核心,我相信这就是您在这里看到的。

有一篇有趣的博客文章,您可能会here