2013-11-24 1 views
2

После выглядящего Fork/Join Tutorial, я создал класс для вычисления больших факториалов:Как определить правильный порог работы деления вилки присоединиться задачами

public class ForkFactorial extends RecursiveTask<BigInteger> { 

    final int end; 
    final int start; 
    private static final int THRESHOLD = 10; 

    public ForkFactorial(int n) { 
     this(1, n + 1); 
    } 

    private ForkFactorial(int start, int end) { 
     this.start = start; 
     this.end = end; 
    } 

    @Override 
    protected BigInteger compute() { 
     if (end - start < THRESHOLD) { 
      return computeDirectly(); 
     } else { 
      int mid = (start + end)/2; 
      ForkFactorial lower = new ForkFactorial(start, mid); 
      lower.fork(); 
      ForkFactorial upper = new ForkFactorial(mid, end); 
      BigInteger upperVal = upper.compute(); 
      return lower.join().multiply(upperVal); 
     } 
    } 

    private BigInteger computeDirectly() { 
     BigInteger val = BigInteger.ONE; 
     BigInteger mult = BigInteger.valueOf(start); 
     for (int iter = start; iter < end; iter++, mult = mult.add(BigInteger.ONE)) { 
      val = val.multiply(mult); 
     } 
     return val; 
    } 
} 

У меня есть вопрос, как определить порог, для которого Я разделяю задачу? Я нашел page on fork/join parallelism, который гласит:

Одна из основных вещей, которые необходимо учитывать при реализации алгоритма с помощью вилки/нарисуй параллелизм они выбрали порог, который определяет будет ли задача выполнить последовательное вычисление, а не разветвление параллельно подзадачи.

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

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

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

Итак, какие эксперименты мне нужно будет сделать, чтобы определить порог?

+0

Мне интересно, что вы достигли в своем расследовании. См. Http://stackoverflow.com/questions/22191369/fork-join-optimization, пожалуйста. Можете ли вы поделиться со мной результатами? –

ответ

4

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

1

Как я понимаю, этот эксперимент является оптимизацией, поэтому его следует применять только тогда, когда есть необходимость.

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

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

2

Обратите внимание, что арифметика не является постоянной с BigInteger, она пропорциональна длине входов. Фактическая сложность каждой операции не всегда составляет hand, хотя реализация futureboy, упомянутая в этом разделе Q/A, документирует то, что она (ожидает) достигла в разных обстоятельствах.

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

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

4

Выбор порога зависит от многих факторов:

Фактическое вычисление должно принять разумное количество времени.Если вы суммируете массив и массив мал, то, вероятно, лучше сделать это последовательно. Если длина массива равна 16 М, то следует разделить ее на более мелкие куски и параллельную обработку. Попробуй и посмотри.

Количество процессоров должно быть достаточным. Дуг Ли когда-то задокументировал свою инфраструктуру процессорами с числом 16+, чтобы сделать ее стоящей. Даже разделение массива пополам и работа на двух потоках даст примерно 1,3% прироста пропускной способности. Теперь вам нужно рассмотреть накладные расходы split/join. Попробуйте запустить множество конфигураций, чтобы узнать, что вы получаете.

Количество одновременных запросов должно быть небольшим. Если у вас есть N процессоров и 8 (N) одновременных запросов, то использование одного потока для каждого запроса часто более эффективно для пропускной способности. Логика здесь проста. Если у вас есть N процессоров, и вы разложите свою работу соответственно, но впереди вас ждут сотни других задач, тогда в чем смысл расщепления?

Это то, что экспериментирует.

К сожалению, этот механизм не оснащен средствами отчетности. Невозможно увидеть нагрузку на каждый поток. Высокий знак воды в deques. Обработано общее количество запросов. Обнаруженные ошибки и т. Д.

Удачи.

Смежные вопросы