Как я пишу задачи? (найдите что-либо подобное коду),

Я впечатлен стандартными блоками потока Intel. Мне нравится, как я должен записать задачу и не код потока, и мне нравится, как это работает под капотом с моим ограниченным пониманием (задача находятся в пуле, там привычка быть 100 потоками на 4cores, задача, как гарантируют, не будет работать, потому что это не находится на своем собственном потоке и может быть далеко в пул. Но это может быть выполнено с другой связанной задачей, таким образом, Вы наклоняетесь, делают плохие вещи как типичный поток небезопасный код).

Я хотел знать больше о задаче записи. Мне нравится 'Многопоточность на основе задач - Как Программировать для видео 100 ядер здесь http://www.gdcvault.com/sponsor.php?sponsor_id=1 (в настоящее время предпоследняя ссылка. ПРЕДУПРЕЖДЕНИЕ его не является 'большим'). Моя fav часть 'решала лабиринт, лучше сделан параллельно', который является вокруг 48 минимальных меток (можно нажать на ссылку на левой стороне. Та часть - действительно все, что необходимо наблюдать если таковые имеются).

Однако мне нравится видеть больше примеров кода и некоторый API того, как записать задачу. У кого-либо есть хороший ресурс? Я понятия не имею, как класс или части кода могут заботиться о продвижении его на пул или как странный код может посмотреть, когда необходимо сделать копию из всего и сколько из всего продвинуто на пул.

11
задан 11 May 2010 в 22:47
поделиться

2 ответа

В Java есть структура параллельных задач, похожая на Thread Building Blocks - она называется Fork-Join framework. Он доступен для использования в текущей версии Java SE 6 и будет включен в предстоящую версию Java SE 7.

В дополнение к документации класса javadoc имеются ресурсы для начала работы с фреймворком. На странице jsr166 упоминается следующее. "Существует также вики, содержащая дополнительную документацию, заметки, советы, примеры и так далее для этих классов."

Примеры fork-join, такие как умножение матриц, являются хорошим местом для начала.

Я использовал фреймворк fork-join при решении некоторых потоковых задач Intel 2009 года. Фреймворк легкий и не требует больших затрат - мой был единственной Java-задачей для задачи Kight's Tour, и он превзошел другие задачи в соревновании. Исходники java и описание доступны для скачивания на сайте конкурса.

EDIT:

Я понятия не имею, как класс или куски кода могут выглядеть после того, как их поместили в пул [...]

Вы можете создать свою собственную задачу, подклассифицировав один из подклассов ForKJoinTask, например RecursiveTask. Вот как вычислить последовательность Фибоначчи параллельно. (Взято из javadocs RecursiveTask - комментарии мои.)

 // declare a new task, that itself spawns subtasks. 
 // The task returns an Integer result.
 class Fibonacci extends RecursiveTask<Integer> {
   final int n;      // the n'th number in the fibonacci sequence to compute
   Fibonnaci(int n) { this.n = n; } // constructor
   Integer compute() {   // this method is the main work of the task
     if (n <= 1)         // 1 or 0, base case to end recursion
        return n;
     Fibonacci f1 = new Fibonacci(n - 1);  // create a new task to compute n-1
     f1.fork();                            // schedule to run asynchronously
     Fibonacci f2 = new Fibonacci(n - 2);  // create a new task to compute n-2
     return f2.invoke() + f1.join();       // wait for both tasks to compute.
       // f2 is run as part of this task, f1 runs asynchronously. 
       // (you could create two separate tasks and wait for them both, but running
       // f2 as part of this task is a little more efficient.
   }
 }

Затем вы запускаете эту задачу и получаете результат

// default parallelism is number of cores
ForkJoinPool pool = new ForkJoinPool(); 
Fibonacci f = new Fibonacci(100);
int result = pool.invoke(f);

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

[...] или как странно может выглядеть код, когда вам нужно сделать копию всего и как много всего выталкивается в пул.

В пул помещаются только сами задачи. В идеале вы не хотите ничего копировать: чтобы избежать вмешательства и необходимости блокировки, которая замедлит работу программы, ваши задачи в идеале должны работать с независимыми данными. Данные, доступные только для чтения, могут быть общими для всех задач, и их не нужно копировать. Если потокам необходимо совместно построить какую-то большую структуру данных, лучше всего, если они будут строить ее по отдельности, а затем объединять в конце. Объединение может быть выполнено как отдельная задача, или каждая задача может добавить свой кусочек головоломки к общему решению. Это часто требует некоторой формы блокировки, но это не является значительной проблемой производительности, если работа задачи намного больше, чем работа по обновлению решения. В моем решении Knight's Tour этот подход используется для обновления общего хранилища туров на доске.

Работа с задачами и параллелизмом - это довольно большой сдвиг парадигмы по сравнению с обычным однопоточным программированием. Часто существует несколько вариантов решения поставленной задачи, но только некоторые из них будут пригодны для потокового решения. Может потребоваться несколько попыток, чтобы понять, как переформулировать знакомые проблемы в многопоточном виде. Лучший способ научиться - посмотреть примеры, а затем попробовать самому. Всегда проверяйте эффект от изменения количества потоков. Вы можете явно задать количество потоков (ядер), используемых в пуле, в конструкторе пула. Если задачи разбиты линейно, можно ожидать почти линейного ускорения при увеличении числа потоков.

7
ответ дан 3 December 2019 в 11:03
поделиться

Игра с "фреймворками", которые утверждают, что решают неразрешимую задачу (оптимальное планирование задач - сложная задача NP), совсем не поможет вам - чтение книг и статей о параллельных алгоритмах поможет. Так называемые «задачи» — не что иное, как причудливое название для определения отделимости задачи (части, которые могут быть вычислены независимо друг от друга). Класс разделимых задач очень мал - и они уже освещены в старых книгах.

Для задач, которые нельзя разделить, необходимо спланировать этапы и барьеры данных между этапами для обмена данными. Оптимальная организация барьеров данных для одновременного обмена данными — это не просто NP-сложно, но и невозможно решить в общем виде в принципе — вам нужно изучить историю всех возможных чередований — это похоже на набор мощности уже экспоненциального набора ( как переход от N к R в математике).Причина, по которой я упоминаю, состоит в том, чтобы прояснить, что никакое программное обеспечение никогда не сможет сделать это за вас, и то, как это сделать, неразрывно зависит от фактического алгоритма и от того, возможно ли вообще распараллеливание (даже если оно теоретически возможно).

Когда вы переходите на высокий параллелизм, вы даже не можете поддерживать очередь, у вас больше нет даже шины памяти — представьте, что 100 ЦП пытаются синхронизироваться только с одним общим целым числом или пытаются выполнить арбитраж шины памяти. . Вы должны заранее спланировать и предварительно настроить все, что будет работать, и, по сути, доказать правильность на белой доске. Intel Threading Building Blocks — это маленький ребенок в этом мире. Они предназначены для небольшого количества ядер, которые все еще могут совместно использовать шину памяти. Запускать отдельные задачи несложно, и вы можете обойтись без какой-либо «каркаса».

Итак, вы снова вынуждены читать как можно больше различных параллельных алгоритмов. Обычно требуется 1-3 года, чтобы исследовать примерно оптимальную схему барьера данных для одной проблемы. Это становится макетом, когда вы выбираете, скажем, 16+ ядер на одном чипе, поскольку только первые соседи могут эффективно обмениваться данными (в течение одного цикла барьера данных). Таким образом, вы на самом деле узнаете гораздо больше, изучая CUDA, документы и результаты с экспериментальным 30-ядерным процессором IBM, чем коммерческие предложения Intel или какую-нибудь игрушку Java.

Остерегайтесь демонстрационных задач, для которых размер потерянных ресурсов (количество ядер и памяти) намного больше, чем достигнутое ими ускорение. Если для решения чего-то в 2 раза быстрее требуется 4 ядра и 4x RAM, решение не масштабируется для распараллеливания.

0
ответ дан 3 December 2019 в 11:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: