Является ли подход параллелизма хорошей идеей для ускорения длинной итерации? - PullRequest
2 голосов
/ 28 августа 2010

У меня есть приложение, которое выполняет итерацию для создания точек на графике с течением времени.В то время как я собираю данные для каждой точки по оси X, я также должен выполнить рекурсивный поиск, что фактически означает, что у меня есть цикл внутри другого цикла.Это не слишком хорошо масштабируется.Я не вижу много примеров использования решения «разделяй и властвуй» на итерациях.Я думал об использовании среды параллелизма Java Executor для запуска каждого цикла в своем собственном потоке, ожидания ответов, сбора результатов и их возврата.Первые результаты теста, которые я получаю, не кажутся намного быстрее.Я знаю, что должен показать некоторый код, но сначала я хочу знать, есть ли у этого подхода преимущества по сравнению с лучшими методами, с которыми я, возможно, не знаком.Заранее спасибо!

Добавление некоторого groovyish / javaish псевдокода, чтобы помочь обдумать это:

class Car {
    id
    model 
    make
    weight
}

for (number in listOfImportantCarIDs) {
    Car car = carsMap.get(number) // find the car we care about
    String maker = car.make //get it's 'parent' 

    // get amount of all related cars
    Iterator<Car> allcars = carsMap.values().iterator();
    while (allcars.hasNext()) {
        Car aCar = alldocs.next();
        if (maker.equals(aCar.make)) {
            totalCarCount++;  // increment total related cars 
            BigDecimal totalWeightofAllCars = totalWeightofAllCars.add(aCar.getWeight()); // add weight to total

            // a ghetto cache to prevent double  counting
            countedMaufacturers.add(make); 
        }     
    }
}

Ответы [ 7 ]

2 голосов
/ 28 августа 2010

Это зависит от того, что делает ваши петли медленными. Они выполняют запросы к базе данных? Доступ к жесткому диску? Иначе делать что-то, что заставляет их ждать внешней операции ввода-вывода? В этом случае лучше всего начинать добавлять потоки до тех пор, пока вы не перестанете видеть их доходность, вам в основном придется настраивать их.

Если они медленны просто из-за необработанной обработки в памяти в Java, то вы можете попробовать добавить поток на каждое ядро ​​ЦП на вашей машине, но, вероятно, не увидите в этом особой выгоды.

2 голосов
/ 28 августа 2010

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

Возможно, если вы подробно опишите проблему, которую вы пытаетесь решить, и ваше текущее решение, мы могли бы помочь здесь.

Редактировать: Боже мой, найти гораздо лучший алгоритм совсем не сложно:

for (Car car : cars {
    Stats s = stats.get(car.maker);
    if (s == null) {
        s = new Stats();
        stats.put(car.maker, s);
    }
    stats.count++;
    stats.totalWeight+=car.weight;
}

for (Car car in importantCars) {
    stats.get(car.maker);
}

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

2 голосов
/ 28 августа 2010

Если задача для вычисления значения y для каждого значения x является полностью атомарной для каждого значения x, то я думаю, что это хорошо подходит для службы исполнителя. Большинство вопросов производительности просто требуют измерения, даже после долгих рассуждений о решении. Оптимальное количество потоков для задач, связанных с процессором, равно p или p + 1, имейте это в виду.

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

Не зная вашей точной проблемы, трудно дать точный ответ.

1 голос
/ 28 августа 2010

Если ваши «исходные» данные не изменены вашим алгоритмом или каждая итерация работает только со своими собственными данными (не изменяет соседние данные), это может дать вам (максимум) 2-кратное увеличение скорости на двухъядерном процессоре.

Это не очень хорошее решение, и с течением времени для вашего текущего решения оно вырастет до 1/2, что все еще довольно дорого, если вы находитесь в цикле с двойной вложенностью. O (X ^ 2/2) все еще в значительной степени равно O (X ^ 2).

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

0 голосов
/ 28 августа 2010

Может ли каждая точка вдоль оси X вычисляться параллельно? Если это так, это ваша возможность для повышения производительности с помощью многопоточности.

Фреймворк Fork-Join сделает программу такого типа простой. Вы можете получить версию с ранним доступом или подражать ей в некоторой степени.

0 голосов
/ 28 августа 2010

"петля внутри другой петли", которая должна звонить в колокольчики;). Внешний цикл всегда ждет внутреннего. Так что это последовательное выполнение и использование потоков не изменится немного. Если каждый цикл не записывает результат в центральную службу, к которой можно обратиться с помощью следующего события (цикла) на вашей оси X. Так что служба будет с состоянием ...

0 голосов
/ 28 августа 2010

Я не думаю, что параллелизм может сделать ваше приложение быстрее. это может помочь вам запустить несколько задач в вашем приложении, но не сделает их быстрее.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...