Эрланг считает, что возраст?

1

Привет, ребята, я пытаюсь создать генератор нагрузки, и моя цель - сравнить, сколько из моих системных ресурсов потребляется при нерестах процессов Erlang по сравнению с нерестовыми потоками (Java). Я делаю это, имея в виду, что программа насчитывает 1000000000 10 раз. Java занимает примерно 35 секунд, чтобы закончить весь процесс с помощью 10 созданных нитей, Erlang занимает много времени с 10 процессами, я с нетерпением ждал этого, потому что он потратил более 4 минут на подсчет. Если я просто сделаю Erlang и Java до 1000000000 без появления потоков/процессов, Erlang займет 1 минуту и 32 секунды, а Java займет около 3 секунд. Я знаю, что Эрланг не предназначен для хрустких чисел, но эта разница вызывает тревогу, почему существует такая большая разница? Оба используют мой процессор до 100%, но не всплеск в ОЗУ. Я не уверен, какие другие методы могут быть использованы для этого сравнения, я также открыт для любых предложений.

вот код для обеих версий

-module(loop).

-compile(export_all).


start(NumberOfProcesses) ->
loop(0, NumberOfProcesses).

%%Processes to spawn
loop(A, NumberOfProcesses) -> 
if A < NumberOfProcesses -> 
    spawn(loop, outerCount, [0]),
    loop(A+1, NumberOfProcesses);   

    true -> ok
end.

%%outer loop 
outerCount(A) ->
if A < 10 ->

    innerCount(0),
    outerCount(A + 1);

    true -> ok
end.

%%inner loop 
innerCount(A) ->
if A < 1000000000 ->
    innerCount(A+1);

    true -> ok
end.

и java

import java.util.Scanner;

class Loop implements Runnable 
{

public static void main(String[] args) 
{

    System.out.println("Input number of processes");
    Scanner scan = new Scanner(System.in);        
    String theNumber = scan.nextLine();   


    for (int t = 0; t < Integer.parseInt(theNumber); t++)
    {
        new Thread(new Loop()).start();
    }
}

public void run() 
{
    int i;
    for (i = 0; i < 10; i++)
    {
        for (int j = 0; j < 1000000000; j++);
    }
}
}
Теги:
multithreading
erlang

3 ответа

2

Ответ RichardC дает некоторое представление, чтобы понять разницу времени выполнения. Я также добавлю, что если ваш Java-код скомпилирован, это может принести много пользы от интеллектуального разветвления микропроцессора и, таким образом, лучше использовать память кеша.

Но тем более важным, на мой взгляд, является то, что вы не выбираете правильное соотношение Process/processing для оценки стоимости нереста процесса.

Тест использует 10 процессов, которые выполняют некоторую значительную работу. Я бы выбрал тест, в котором много процессов порождаются (несколько тысяч? Я не знаю, сколько потоков JVM может управлять), каждый процесс делает очень мало вещей, например, этот код, который порождает на каждом шаге в два раза количество процессов и дождитесь, когда самые глубокие процессы будут отправлены назад. С глубиной 17, что означает 262143 процессов в общей сложности и 131072 возвращенных сообщений, на мой очень медленный ПК требуется менее 0,5 с, то есть менее 2 мкс на процесс (конечно, следует использовать двухъядерную двойную нить)

-module (cascade).

-compile([export_all]).


test() ->
    timer:tc(?MODULE,start,[]).

start() ->
    spawn(?MODULE,child,[self(),17]),
    loop(1024*128).

loop(0) -> done;
loop(N) ->
    receive
        done -> loop(N-1)
    end.

child(P,0) -> P ! done;
child(P,N) ->
    spawn(?MODULE,child,[P,N-1]),
    spawn(?MODULE,child,[P,N-1]).
  • 0
    Я думаю, что код, который вы написали только сейчас, это то, что я могу искать, вы не возражаете, если бы я использовал его? У меня есть несколько вопросов по этому поводу, хотя почему 1024 * 128? почему бы просто не написать 131072? и как процессы 262143 возвращают 131072 сообщения? также не должно быть 262142? Я рассчитал это, и это подходит к этому. «Конечно, следует использовать двухъядерный двойной поток» означает? В большинстве случаев я новичок, поэтому, пожалуйста, прости мое невежество.
  • 0
    Другой вопрос, есть ли способ, которым я могу подражать то же самое в Java? Я хочу иметь одинаковый тест для обоих.
Показать ещё 3 комментария
2

Вы используете 32- или 64-битную версию Erlang? Если это 32 бит, тогда предел внутреннего контура 1000000000 не будет вписываться в однословное fixnum (максимум 28 бит, включая знак), и цикл начнет выполнять арифметику бинума в куче, которая намного дороже, чем просто увеличивая число слов и цикл (это также приведет к тому, что сбор мусора будет происходить и сейчас, чтобы избавиться от старых неиспользуемых чисел из кучи). Изменение внешнего цикла с 10 до 1000 и удаление 2 нулей соответственно из внутреннего цикла должны сделать его арифметикой fixnum только на бит 32- BEAM.

Затем также возникает вопрос о том, действительно ли версия Java фактически выполняет какую-либо работу, или если цикл в какой-то момент оптимизируется до no-op. (Компилятор Erlang не делает такого трюка - по крайней мере, пока нет.)

  • 0
    Я использую 32-битную версию Erlang.
0

Здесь есть несколько проблем.

Я не знаю, как вы можете оценить, что делает компилятор Java, но я бы поставил ему задачу оптимизировать цикл из существования. Я думаю, вам нужно будет сделать цикл, чтобы сделать какое-то сравнение.

Что еще более важно, код Erlang не делает то, что вы думаете, что он делает, насколько я могу судить. Кажется, что каждый процесс насчитывает до 1000000000, а затем делает это снова в общей сложности в 10 раз.

Возможно, хуже, ваши функции не являются хвостовыми рекурсивными, поэтому ваши функции продолжают накапливаться в памяти, ожидая выполнения последней. (Edit: Возможно, я ошибаюсь. Не привык к утверждению if.)

Здесь Erlang делает то, что вы хотите. Он все еще очень медленный.

-module(realloop).
-compile(export_all).

start(N) ->
    loop(0, N).

loop(N, N) ->
    io:format("Spawned ~B processes~n", [N]);
loop(A, N) ->
    spawn(realloop, count, [0, 1000000000]),
    loop(A+1, N).

count(Upper, Upper) ->
    io:format("Reached ~B~n", [Upper]);
count(Lower, Upper) ->
    count(Lower+1, Upper).
  • 0
    Ваш код кажется короче и лучше в целом. Я не профессионал в Erlang, я начал заниматься этим около месяца назад. Да, я хочу, чтобы он считал до 1000000000 в 10 раз точно так же, как это делает Java. Я думал, что мои функции будут по-прежнему считаться хвостовыми рекурсивами, если он будет вызываться последним независимо от того, в каком состоянии он находится, если он или нет

Ещё вопросы

Сообщество Overcoder
Наверх
Меню