След: Существенные Классы
Урок: Параллелизм
Раздел: Высокоуровневые Объекты Параллелизма
Подраздел: Исполнители
Ветвление/Соединение
Домашняя страница > Существенные Классы > Параллелизм

Ветвление/Соединение

Новый в Java SE 7 выпусков, платформа ветвления/соединения является реализацией ExecutorService интерфейс, который помогает Вам использовать в своих интересах многократные процессоры. Это разрабатывается для работы, которая может быть повреждена в мелкие кусочки рекурсивно. Цель состоит в том, чтобы использовать всю доступную вычислительную мощность, чтобы улучшить производительность Вашего приложения.

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

Центр платформы ветвления/соединения ForkJoinPool class, расширение AbstractExecutorService. ForkJoinPool реализует базовый крадущий работу алгоритм и может выполниться ForkJoinTasks.

Основное Использование

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

if (my portion of the work is small enough)
  do the work directly
else
  split my work into two pieces
  invoke the two pieces and wait for the results

Оберните этот код как a ForkJoinTask подкласс, обычно как один из его более специализированных типов RecursiveTask(который может возвратить результат), или RecursiveAction.

После Вашего ForkJoinTask готово, создайте тот, который представляет всю работу, которая будет сделана и будет передавать это к invoke() метод a ForkJoinPool экземпляр.

Размывание для Ясности

Чтобы помочь Вам понять, как платформа ветвления/соединения работает, рассмотрите простой пример. Предположите, что Вы хотите выполнить простую размытость на изображении. Изображение первоисточника представляется массивом целых чисел, где каждое целое число содержит значения цвета для единственного пикселя. Размытое целевое изображение также представляется целочисленным массивом с тем же самым размером как источник.

Выполнение размытости выполняется, работая через исходный массив один пиксель за один раз. Каждый пиксель усредняется с его окружающими пикселями (красные, зеленые, и синие компоненты усредняются), и результат помещается в целевой массив. Вот одна возможная реализация:

public class ForkBlur extends RecursiveAction {
    private int[] mSource;
    private int mStart;
    private int mLength;
    private int[] mDestination;
  
    // Processing window size, should be odd.
    private int mBlurWidth = 15;
  
    public ForkBlur(int[] src, int start, int length, int[] dst) {
        mSource = src;
        mStart = start;
        mLength = length;
        mDestination = dst;
    }

    protected void computeDirectly() {
        int sidePixels = (mBlurWidth - 1) / 2;
        for (int index = mStart; index < mStart + mLength; index++) {
            // Calculate average.
            float rt = 0, gt = 0, bt = 0;
            for (int mi = -sidePixels; mi <= sidePixels; mi++) {
                int mindex = Math.min(Math.max(mi + index, 0),
                                    mSource.length - 1);
                int pixel = mSource[mindex];
                rt += (float)((pixel & 0x00ff0000) >> 16)
                      / mBlurWidth;
                gt += (float)((pixel & 0x0000ff00) >>  8)
                      / mBlurWidth;
                bt += (float)((pixel & 0x000000ff) >>  0)
                      / mBlurWidth;
            }
          
            // Re-assemble destination pixel.
            int dpixel = (0xff000000     ) |
                   (((int)rt) << 16) |
                   (((int)gt) <<  8) |
                   (((int)bt) <<  0);
            mDestination[index] = dpixel;
        }
    }
  
  ...

Теперь Вы реализуете краткий обзор compute() метод, который или выполняет размытость непосредственно или разделяет ее на две меньших задачи. Простой порог длины массива помогает определить, выполняется ли работа или разделяется.

protected static int sThreshold = 100000;

protected void compute() {
    if (mLength < sThreshold) {
        computeDirectly();
        return;
    }
    
    int split = mLength / 2;
    
    invokeAll(new ForkBlur(mSource, mStart, split, mDestination),
              new ForkBlur(mSource, mStart + split, mLength - split,
                           mDestination));
}

Если предыдущие методы находятся в подклассе RecursiveAction class, устанавливая это, чтобы работать в a ForkJoinPool является прямым.

Создайте задачу, которая представляет всю работу, которая будет сделана.

// source image pixels are in src
// destination image pixels are in dst
ForkBlur fb = new ForkBlur(src, 0, src.length, dst);

Создайте ForkJoinPool это выполнит задачу.

ForkJoinPool pool = new ForkJoinPool();

Выполните задачу.

pool.invoke(fb);

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


Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Пулы потоков
Следующая страница: Параллельные Наборы



Spec-Zone.ru - all specs in one place