Erlang на многоядерном процессоре - PullRequest
17 голосов
/ 10 августа 2011

Я изучаю эрланг и очень впечатлен тем, как легко распараллелить работу.Чтобы немного попрактиковаться, я выкопал хорошую последовательность Фибаноччи.В следующем коде я пытаюсь воспользоваться преимуществами распараллеливания, вычисляя по три дорогих продукта за раз.

-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 ]

15 голосов
/ 10 августа 2011

По умолчанию Эрланг по умолчанию запускал один планировщик, который по сути является собственным потоком ОС, который выбирает задачи Erlang для запуска из очереди.С появлением многоядерных и многопроцессорных систем время выполнения было расширено, чтобы воспользоваться преимуществами.Запуск среды выполнения с -smp enabled приведет к тому, что среда выполнения создаст несколько планировщиков, обычно по одному на логический ЦП.Вы можете вручную указать количество планировщиков с помощью флага -S, например, -S 16.

Это задокументировано в Справочном руководстве по системе исполнения Erlang .

Более подробное обсуждение поддержки SMP можно найти в этой ветке обсуждения .

EDIT

Я должен также отметить, что с R12B,SMP включен по умолчанию на платформах, которые его поддерживают (эквивалент флага -smp auto).Если вас интересует ваша собственная среда выполнения, вас может заинтересовать следующая цитата из ветки обсуждения:

Вы можете увидеть, что было выбрано в первой строке распечатки из команды "erl".Например, эмулятор Erlang (BEAM) версии 5.6.4 [source] [smp: 4] [asynch-threads: 0] .....

«[smp: 4]» выше говорит о том, что SMP VMзапускается и с 4 планировщиками.

9 голосов
/ 19 августа 2011

Причина, по которой вы видите такой небольшой параллелизм, заключается в том, что ваша программа в основном последовательная.Вся работа выполняется в одном процессе в функции fib / 3.Все процессы, которые вы порождаете, просто отправляют сообщение, а затем умирают, и процесс порождения синхронно ожидает эти сообщения, поэтому реального параллелизма не происходит.С таким же успехом можно просто вызвать функцию loop / 3 с этими значениями.

В противном случае, как уже упоминали другие, Erlang автоматически использует все доступные несколько ядер и распределяет процессы между ними, где это возможно.В вашем случае, однако, в этом нет особой необходимости, и нет никакой выгоды, поэтому система не делает этого.

Это на самом деле одна из самых сложных вещей при написании параллельных приложений.Недостаточно просто распределить вещи по многим процессам, вам нужно убедиться, что эти процессы действительно работают одновременно.Это означает переосмысление ваших алгоритмов, что может быть сложно.

6 голосов
/ 10 августа 2011

Эрланг не использует темы в традиционном смысле. Erlang VM создает один системный поток для каждого аппаратного ядра ЦП. Когда вы запускаете поток в Erlang, вы действительно создаете «задачу», которая отличается от системного потока. Эрланг управляет этими задачами внутри виртуальной машины.

В зависимости от виртуальной машины и ее конфигурации, эти задачи могут или не могут быть сопоставлены с отдельными ядрами процессора, что, я считаю, именно то, что вы видите здесь.

Есть интересная статья в блоге, которая вам может понравиться здесь .

...