Я изучаю эрланг и очень впечатлен тем, как легко распараллелить работу.Чтобы немного попрактиковаться, я выкопал хорошую последовательность Фибаноччи.В следующем коде я пытаюсь воспользоваться преимуществами распараллеливания, вычисляя по три дорогих продукта за раз.
-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) работают только одно-два ядра, а остальные бездельничают.
Мои вопросы:
- Кто решает, на сколько ядер распределены рабочие потоки?Узел erlang или моя ОС (ubuntu с 2.6.38 в моем случае)?
- Потеряю ли я скорость из-за того, что два или три ядра работают на холостом ходу?