Параллельные вычисления — это тип вычислений, в которых одновременно выполняется множество вычислений или процессов . [1] Большие проблемы часто можно разделить на более мелкие, которые затем можно решить одновременно. Существует несколько различных форм параллельных вычислений: параллелизм на уровне битов , на уровне инструкций , данных и задач . Параллелизм уже давно используется в высокопроизводительных вычислениях , но приобрел более широкий интерес из-за физических ограничений, препятствующих масштабированию частоты . [2] Поскольку потребление энергии (и, следовательно, выделение тепла) компьютерами стало проблемой в последние годы, [3] параллельные вычисления стали доминирующей парадигмой в компьютерной архитектуре , в основном в форме многоядерных процессоров . [4]
В информатике параллелизм и параллелизм — это две разные вещи: параллельная программа использует несколько ядер ЦП , каждое ядро выполняет задачу независимо. С другой стороны, параллелизм позволяет программе справляться с несколькими задачами даже на одном ядре ЦП; ядро переключается между задачами (т. е. потоками ) , не обязательно завершая каждую из них. Программа может иметь обе характеристики, ни одну из них или комбинацию характеристик параллелизма и параллелизма. [5]
Параллельные компьютеры можно грубо классифицировать по уровню, на котором оборудование поддерживает параллелизм, с многоядерными и многопроцессорными компьютерами, имеющими несколько процессорных элементов в пределах одной машины, в то время как кластеры , MPP и сетки используют несколько компьютеров для работы над одной и той же задачей. Специализированные архитектуры параллельных компьютеров иногда используются вместе с традиционными процессорами для ускорения определенных задач.
В некоторых случаях параллелизм прозрачен для программиста, например, в параллелизме на уровне битов или на уровне инструкций, но явно параллельные алгоритмы , особенно те, которые используют параллелизм, сложнее писать, чем последовательные , [6], поскольку параллелизм вводит несколько новых классов потенциальных ошибок программного обеспечения , из которых наиболее распространены состояния гонки . Связь и синхронизация между различными подзадачами, как правило, являются одними из самых больших препятствий для получения оптимальной производительности параллельной программы.
Теоретическая верхняя граница ускорения отдельной программы в результате распараллеливания определяется законом Амдаля , который гласит , что оно ограничено долей времени, в течение которого может использоваться распараллеливание.
Традиционно компьютерное программное обеспечение писалось для последовательных вычислений . Для решения проблемы алгоритм конструируется и реализуется как последовательный поток инструкций. Эти инструкции выполняются на центральном процессоре одного компьютера. Только одна инструкция может выполняться за раз — после того, как эта инструкция будет завершена, выполняется следующая. [7]
Параллельные вычисления, с другой стороны, используют несколько элементов обработки одновременно для решения задачи. Это достигается путем разбиения задачи на независимые части, так что каждый элемент обработки может выполнять свою часть алгоритма одновременно с другими. Элементы обработки могут быть разнообразными и включать такие ресурсы, как один компьютер с несколькими процессорами, несколько сетевых компьютеров, специализированное оборудование или любую комбинацию вышеперечисленного. [7] Исторически параллельные вычисления использовались для научных вычислений и моделирования научных проблем, особенно в естественных и технических науках , таких как метеорология . Это привело к разработке параллельного оборудования и программного обеспечения, а также высокопроизводительных вычислений . [8]
Масштабирование частоты было основной причиной улучшения производительности компьютеров с середины 1980-х до 2004 года. Время выполнения программы равно количеству инструкций, умноженному на среднее время на инструкцию. Сохраняя все остальное постоянным, увеличение тактовой частоты уменьшает среднее время, необходимое для выполнения инструкции. Таким образом, увеличение частоты уменьшает время выполнения всех программ, связанных с вычислениями . [9] Однако энергопотребление P чипом определяется уравнением P = C × V 2 × F , где C — емкость , переключаемая за такт (пропорциональна количеству транзисторов, входы которых изменяются), V — напряжение , а F — частота процессора (циклов в секунду). [10] Увеличение частоты увеличивает количество энергии, используемой процессором. Рост энергопотребления процессора в конечном итоге привёл к отмене компанией Intel 8 мая 2004 года процессоров Tejas и Jayhawk , что обычно называют концом масштабирования частоты как доминирующей парадигмы компьютерной архитектуры. [11]
Чтобы справиться с проблемой энергопотребления и перегрева основного центрального процессора (ЦП или процессора), производители начали выпускать энергоэффективные процессоры с несколькими ядрами. Ядро является вычислительным блоком процессора, а в многоядерных процессорах каждое ядро независимо и может одновременно обращаться к одной и той же памяти. Многоядерные процессоры принесли параллельные вычисления на настольные компьютеры . Таким образом, распараллеливание последовательных программ стало основной задачей программирования. В 2012 году четырехъядерные процессоры стали стандартом для настольных компьютеров , в то время как серверы имеют 10+ ядерных процессоров. Из закона Мура можно предсказать, что количество ядер на процессор будет удваиваться каждые 18–24 месяца. Это может означать, что после 2020 года типичный процессор будет иметь десятки или сотни ядер, однако на самом деле стандарт находится где-то в районе 4–16 ядер, при этом некоторые конструкции имеют смесь производительных и эффективных ядер (например, конструкция big.LITTLE от ARM ) из-за тепловых и конструктивных ограничений. [12] [ необходима ссылка ]
Операционная система может гарантировать, что различные задачи и пользовательские программы будут выполняться параллельно на доступных ядрах. Однако для того, чтобы последовательная программа в полной мере использовала многоядерную архитектуру, программисту необходимо реструктурировать и распараллелить код. Ускорение времени выполнения прикладного программного обеспечения больше не будет достигаться за счет масштабирования частоты, вместо этого программистам необходимо будет распараллеливать свой программный код, чтобы воспользоваться растущей вычислительной мощностью многоядерных архитектур. [13]
Оптимально, ускорение от распараллеливания будет линейным — удвоение числа обрабатывающих элементов должно вдвое сократить время выполнения, а удвоение во второй раз должно снова вдвое сократить время выполнения. Однако очень немногие параллельные алгоритмы достигают оптимального ускорения. Большинство из них имеют почти линейное ускорение для небольшого числа обрабатывающих элементов, которое выравнивается до постоянного значения для большого числа обрабатывающих элементов.
Потенциальное ускорение алгоритма на параллельной вычислительной платформе определяется законом Амдаля [14]
где
Поскольку S latency < 1/(1 - p ) , это показывает, что небольшая часть программы, которая не может быть распараллелена, ограничит общее ускорение, доступное от распараллеливания. Программа, решающая большую математическую или инженерную задачу, обычно состоит из нескольких распараллеливаемых частей и нескольких нераспараллеливаемых (последовательных) частей. Если нераспараллеливаемая часть программы составляет 10% времени выполнения ( p = 0,9), мы можем получить не более чем 10-кратное ускорение, независимо от того, сколько процессоров добавлено. Это накладывает верхний предел на полезность добавления большего количества параллельных исполнительных блоков. «Когда задачу невозможно разбить на разделы из-за последовательных ограничений, приложение дополнительных усилий не влияет на график. Вынашивание ребенка занимает девять месяцев, независимо от того, сколько женщин назначено». [15]
Закон Амдаля применим только к случаям, когда размер проблемы фиксирован. На практике, по мере того, как становится доступно больше вычислительных ресурсов, они, как правило, используются для более крупных задач (больших наборов данных), и время, затрачиваемое на параллелизуемую часть, часто растет гораздо быстрее, чем на изначально последовательную работу. [16] В этом случае закон Густафсона дает менее пессимистичную и более реалистичную оценку параллельной производительности: [17]
Оба закона Амдаля и Густафсона предполагают, что время выполнения последовательной части программы не зависит от количества процессоров. Закон Амдаля предполагает, что вся задача имеет фиксированный размер, так что общий объем работы, которая должна быть выполнена параллельно, также не зависит от количества процессоров , тогда как закон Густафсона предполагает, что общий объем работы, которая должна быть выполнена параллельно, линейно зависит от количества процессоров .
Понимание зависимостей данных имеет основополагающее значение для реализации параллельных алгоритмов . Ни одна программа не может работать быстрее, чем самая длинная цепочка зависимых вычислений (известная как критический путь ), поскольку вычисления, зависящие от предыдущих вычислений в цепочке, должны выполняться по порядку. Однако большинство алгоритмов состоят не только из длинной цепочки зависимых вычислений; обычно существуют возможности выполнять независимые вычисления параллельно.
Пусть P i и P j будут двумя сегментами программы. Условия Бернштейна [18] описывают, когда они независимы и могут выполняться параллельно. Для P i пусть I i будут всеми входными переменными, а O i — выходными переменными, и то же самое для P j . P i и P j независимы, если они удовлетворяют
Нарушение первого условия вводит зависимость потока, соответствующую первому сегменту, производящему результат, используемый вторым сегментом. Второе условие представляет собой антизависимость, когда второй сегмент производит переменную, необходимую первому сегменту. Третье и последнее условие представляет собой выходную зависимость: когда два сегмента записывают в одно и то же место, результат поступает из логически последнего выполненного сегмента. [19]
Рассмотрим следующие функции, демонстрирующие несколько видов зависимостей:
1: функция Dep(a, b)2: с := а * б3: д := 3 * с4: конечная функция
В этом примере инструкция 3 не может быть выполнена до (или даже параллельно) инструкции 2, поскольку инструкция 3 использует результат инструкции 2. Это нарушает условие 1 и, таким образом, вводит зависимость потока.
1: функция NoDep(a, b)2: с := а * б3: д := 3 * б4: е := а + б5: конечная функция
В этом примере между инструкциями нет зависимостей, поэтому их можно выполнять параллельно.
Условия Бернштейна не позволяют разделять память между различными процессами. Для этого необходимы некоторые средства обеспечения порядка между доступами, такие как семафоры , барьеры или какой-либо другой метод синхронизации .
Подзадачи в параллельной программе часто называют потоками . Некоторые параллельные компьютерные архитектуры используют меньшие, легкие версии потоков, известные как волокна , в то время как другие используют большие версии, известные как процессы . Однако «потоки» обычно принимаются как общий термин для подзадач. [20] Потокам часто требуется синхронизированный доступ к объекту или другому ресурсу , например, когда они должны обновить переменную , которая является общей для них. Без синхронизации инструкции между двумя потоками могут чередоваться в любом порядке. Например, рассмотрим следующую программу:
Если инструкция 1B выполняется между 1A и 3A, или если инструкция 1A выполняется между 1B и 3B, программа выдаст неверные данные. Это известно как состояние гонки . Программист должен использовать блокировку для обеспечения взаимного исключения . Блокировка — это конструкция языка программирования, которая позволяет одному потоку взять под контроль переменную и не дать другим потокам читать или записывать ее, пока эта переменная не будет разблокирована. Поток, удерживающий блокировку, может свободно выполнять свою критическую секцию (раздел программы, требующий исключительного доступа к некоторой переменной) и разблокировать данные по ее завершении. Поэтому, чтобы гарантировать правильное выполнение программы, приведенную выше программу можно переписать для использования блокировок:
Один поток успешно заблокирует переменную V, в то время как другой поток будет заблокирован — не сможет продолжить работу, пока V не будет снова разблокирована. Это гарантирует правильное выполнение программы. Блокировки могут быть необходимы для обеспечения правильного выполнения программы, когда потоки должны сериализовать доступ к ресурсам, но их использование может значительно замедлить программу и повлиять на ее надежность . [21]
Блокировка нескольких переменных с использованием неатомарных блокировок приводит к возможности взаимоблокировки программы . Атомарный замок блокирует несколько переменных одновременно. Если он не может заблокировать их все, он не блокирует ни одну из них. Если двум потокам необходимо заблокировать одни и те же две переменные с использованием неатомарных блокировок, возможно, что один поток заблокирует одну из них, а второй поток заблокирует вторую переменную. В таком случае ни один поток не сможет завершиться, и возникнет взаимоблокировка. [22]
Многие параллельные программы требуют, чтобы их подзадачи действовали синхронно . Для этого требуется использование барьера . Барьеры обычно реализуются с помощью блокировки или семафора . [23] Один класс алгоритмов, известный как алгоритмы без блокировки и без ожидания , вообще избегает использования блокировок и барьеров. Однако этот подход, как правило, трудно реализовать и требует правильно спроектированных структур данных. [24]
Не всякое распараллеливание приводит к ускорению. Как правило, по мере того, как задача разбивается на все большее количество потоков, эти потоки тратят все большую часть своего времени на общение друг с другом или ожидание друг у друга доступа к ресурсам. [25] [26] Как только накладные расходы от конкуренции за ресурсы или общения начинают доминировать над временем, затрачиваемым на другие вычисления, дальнейшее распараллеливание (то есть разделение рабочей нагрузки на еще большее количество потоков) увеличивает, а не уменьшает количество времени, требуемого для завершения. Эту проблему, известную как параллельное замедление , [27] в некоторых случаях можно решить путем анализа и перепроектирования программного обеспечения. [28]
Приложения часто классифицируются в зависимости от того, как часто их подзадачам необходимо синхронизироваться или взаимодействовать друг с другом. Приложение демонстрирует мелкозернистый параллелизм, если его подзадачи должны взаимодействовать много раз в секунду; оно демонстрирует грубозернистый параллелизм, если они не взаимодействуют много раз в секунду, и оно демонстрирует смущающий параллелизм, если им редко или никогда не приходится взаимодействовать. Смущающе параллельные приложения считаются самыми простыми для распараллеливания.
Майкл Дж. Флинн создал одну из самых ранних систем классификации параллельных (и последовательных) компьютеров и программ, теперь известную как таксономия Флинна . Флинн классифицировал программы и компьютеры по тому, работали ли они с использованием одного набора или нескольких наборов инструкций, а также по тому, использовали ли эти инструкции один набор или несколько наборов данных.
Классификация «одна инструкция — одни данные» (SISD) эквивалентна полностью последовательной программе. Классификация «одна инструкция — несколько данных» (SIMD) аналогична повторному выполнению одной и той же операции над большим набором данных. Это обычно делается в приложениях обработки сигналов . «Множественные инструкции — одни данные» (MISD) — редко используемая классификация. Хотя были разработаны компьютерные архитектуры для решения этой задачи (например, систолические массивы ), было реализовано лишь несколько приложений, соответствующих этому классу. Программы «многократные инструкции — несколько данных» (MIMD) являются, безусловно, наиболее распространенным типом параллельных программ.
По словам Дэвида А. Паттерсона и Джона Л. Хеннесси , «Некоторые машины, конечно, являются гибридами этих категорий, но эта классическая модель выжила, потому что она проста, легка для понимания и дает хорошее первое приближение. Она также — возможно, из-за своей понятности — является наиболее широко используемой схемой». [30]
С появлением технологии изготовления компьютерных микросхем сверхбольшой интеграционной схемы (VLSI) в 1970-х годах и примерно до 1986 года ускорение в компьютерной архитектуре было обусловлено удвоением размера компьютерного слова — количества информации, которую процессор может обработать за один цикл. [31] Увеличение размера слова уменьшает количество инструкций, которые процессор должен выполнить для выполнения операции над переменными, размеры которых больше длины слова. Например, где 8-битный процессор должен сложить два 16-битных целых числа , процессор должен сначала сложить 8 младших битов из каждого целого числа, используя стандартную инструкцию сложения, затем сложить 8 старших битов, используя инструкцию сложения с переносом, и бит переноса из сложения младшего порядка; таким образом, 8-битному процессору требуются две инструкции для завершения одной операции, тогда как 16-битный процессор сможет выполнить операцию с помощью одной инструкции.
Исторически 4-битные микропроцессоры были заменены 8-битными, затем 16-битными, затем 32-битными микропроцессорами. Эта тенденция в целом закончилась с появлением 32-битных процессоров, которые были стандартом в вычислениях общего назначения в течение двух десятилетий. Только в начале 2000-х годов, с появлением архитектур x86-64 , 64-битные процессоры стали обычным явлением.
Компьютерная программа, по сути, представляет собой поток инструкций, выполняемых процессором. Без параллелизма на уровне инструкций процессор может выдавать только менее одной инструкции за такт ( IPC < 1 ). Такие процессоры известны как субскалярные процессоры. Эти инструкции могут быть переупорядочены и объединены в группы, которые затем выполняются параллельно без изменения результата программы. Это известно как параллелизм на уровне инструкций. Достижения в параллелизме на уровне инструкций доминировали в архитектуре компьютеров с середины 1980-х до середины 1990-х годов. [32]
Все современные процессоры имеют многоступенчатые конвейеры инструкций . Каждая стадия в конвейере соответствует разному действию, которое процессор выполняет над этой инструкцией на этой стадии; процессор с N -ступенчатым конвейером может иметь до N различных инструкций на разных стадиях завершения и, таким образом, может выдавать одну инструкцию за такт ( IPC = 1 ). Эти процессоры известны как скалярные процессоры. Каноническим примером конвейерного процессора является RISC- процессор с пятью стадиями: выборка инструкций (IF), декодирование инструкций (ID), выполнение (EX), доступ к памяти (MEM) и обратная запись регистра (WB). Процессор Pentium 4 имел 35-ступенчатый конвейер. [33]
Большинство современных процессоров также имеют несколько исполнительных блоков . Обычно они объединяют эту функцию с конвейеризацией и, таким образом, могут выдавать более одной инструкции за такт ( IPC > 1 ). Эти процессоры известны как суперскалярные процессоры. Суперскалярные процессоры отличаются от многоядерных процессоров тем, что несколько исполнительных блоков не являются целыми процессорами (т. е. процессорными блоками). Инструкции могут быть сгруппированы вместе, только если между ними нет зависимости данных . Scoreboarding и алгоритм Tomasulo (который похож на scoreboarding, но использует переименование регистров ) являются двумя наиболее распространенными методами реализации внеочередного выполнения и параллелизма на уровне инструкций.
Параллелизм задач — это характеристика параллельной программы, которая заключается в том, что «совершенно разные вычисления могут выполняться либо на одном и том же, либо на разных наборах данных». [34] Это контрастирует с параллелизмом данных, где один и тот же расчет выполняется на одном и том же или на разных наборах данных. Параллелизм задач включает в себя разложение задачи на подзадачи и последующее распределение каждой подзадачи процессору для выполнения. Затем процессоры будут выполнять эти подзадачи одновременно и часто совместно. Параллелизм задач обычно не масштабируется с размером проблемы. [35]
Параллелизм уровня суперслова — это метод векторизации, основанный на развертывании цикла и базовой векторизации блоков. Он отличается от алгоритмов векторизации цикла тем, что может использовать параллелизм встроенного кода , например, манипулирование координатами, цветовыми каналами или в циклах, развернутых вручную. [36]
Основная память в параллельном компьютере является либо общей памятью (совместно используемой всеми процессорными элементами в одном адресном пространстве ), либо распределенной памятью (в которой каждый процессорный элемент имеет свое собственное локальное адресное пространство). [37] Распределенная память относится к тому факту, что память логически распределена, но часто подразумевает, что она также распределена физически. Распределенная общая память и виртуализация памяти объединяют два подхода, где процессорный элемент имеет свою собственную локальную память и доступ к памяти на нелокальных процессорах. Доступ к локальной памяти, как правило, быстрее, чем доступ к нелокальной памяти. На суперкомпьютерах распределенное общее пространство памяти может быть реализовано с использованием модели программирования, такой как PGAS . Эта модель позволяет процессам на одном вычислительном узле прозрачно получать доступ к удаленной памяти другого вычислительного узла. Все вычислительные узлы также подключены к внешней системе общей памяти через высокоскоростное соединение, такое как Infiniband , эта внешняя система общей памяти известна как burst buffer , который обычно строится из массивов энергонезависимой памяти, физически распределенной по нескольким узлам ввода-вывода.
Компьютерные архитектуры, в которых к каждому элементу основной памяти можно получить доступ с одинаковой задержкой и пропускной способностью , известны как системы с равномерным доступом к памяти (UMA). Обычно этого можно достичь только с помощью системы с общей памятью , в которой память физически не распределена. Система, не обладающая этим свойством, известна как архитектура с неоднородным доступом к памяти (NUMA). Системы с распределенной памятью имеют неоднородный доступ к памяти.
Компьютерные системы используют кэши — небольшие и быстрые запоминающие устройства, расположенные близко к процессору, которые хранят временные копии значений памяти (рядом как в физическом, так и в логическом смысле). Параллельные компьютерные системы испытывают трудности с кэшами, которые могут хранить одно и то же значение в нескольких местах, с возможностью неправильного выполнения программы. Этим компьютерам требуется система когерентности кэша , которая отслеживает кэшированные значения и стратегически очищает их, тем самым гарантируя правильное выполнение программы. Отслеживание шины — один из наиболее распространенных методов отслеживания того, к каким значениям осуществляется доступ (и, следовательно, они должны быть очищены). Проектирование больших, высокопроизводительных систем когерентности кэша — очень сложная проблема в компьютерной архитектуре. В результате архитектуры компьютеров с общей памятью не масштабируются так же хорошо, как системы с распределенной памятью. [37]
Связь процессор-процессор и процессор-память может быть реализована на аппаратном уровне несколькими способами, в том числе через общую (многопортовую или мультиплексную ) память, перекрестный коммутатор , общую шину или сеть межсоединений множества топологий, включая звезду , кольцо , дерево , гиперкуб , толстый гиперкуб (гиперкуб с более чем одним процессором в узле) или n-мерную сетку .
Параллельные компьютеры, основанные на взаимосвязанных сетях, должны иметь некую маршрутизацию , чтобы обеспечить передачу сообщений между узлами, которые не соединены напрямую. Среда, используемая для связи между процессорами, вероятно, будет иерархической в больших многопроцессорных машинах.
Параллельные компьютеры можно грубо классифицировать по уровню, на котором оборудование поддерживает параллелизм. Эта классификация в целом аналогична расстоянию между базовыми вычислительными узлами. Они не являются взаимоисключающими; например, кластеры симметричных мультипроцессоров относительно распространены.
Многоядерный процессор — это процессор, который включает в себя несколько процессорных блоков (называемых «ядрами») на одном чипе. Этот процессор отличается от суперскалярного процессора, который включает в себя несколько исполнительных блоков и может выдавать несколько инструкций за такт из одного потока инструкций (потока); напротив, многоядерный процессор может выдавать несколько инструкций за такт из нескольких потоков инструкций. Микропроцессор Cell компании IBM , разработанный для использования в Sony PlayStation 3 , является известным многоядерным процессором. Каждое ядро в многоядерном процессоре также может быть потенциально суперскалярным, то есть на каждом такте каждое ядро может выдавать несколько инструкций из одного потока.
Одновременная многопоточность (из которых наиболее известна технология Intel Hyper-Threading ) была ранней формой псевдомногоядерности. Процессор, способный к параллельной многопоточности, включает несколько исполнительных блоков в одном процессорном блоке — то есть имеет суперскалярную архитектуру — и может выдавать несколько инструкций за такт из нескольких потоков. Временная многопоточность , с другой стороны, включает один исполнительный блок в одном процессорном блоке и может выдавать одну инструкцию за раз из нескольких потоков.
Симметричный мультипроцессор (SMP) — это компьютерная система с несколькими идентичными процессорами, которые совместно используют память и подключаются через шину . [38] Конкуренция за шину препятствует масштабированию архитектуры шины. В результате SMP обычно не включают более 32 процессоров. [39] Из-за небольшого размера процессоров и значительного снижения требований к пропускной способности шины, достигаемого большими кэшами, такие симметричные мультипроцессоры чрезвычайно экономичны, при условии, что существует достаточный объем пропускной способности памяти. [38]
Распределенный компьютер (также известный как многопроцессор с распределенной памятью) — это распределенная система памяти компьютера, в которой элементы обработки соединены сетью. Распределенные компьютеры обладают высокой масштабируемостью. Термины « одновременные вычисления », «параллельные вычисления» и «распределенные вычисления» во многом совпадают, и между ними не существует четкого различия. [40] Одна и та же система может быть охарактеризована как «параллельная» и «распределенная»; процессоры в типичной распределенной системе работают одновременно и параллельно. [41]
Кластер — это группа слабо связанных компьютеров, которые работают вместе в тесном контакте, так что в некоторых отношениях их можно рассматривать как один компьютер. [42] Кластеры состоят из нескольких автономных машин, соединенных сетью. Хотя машины в кластере не обязательно должны быть симметричными, балансировка нагрузки становится более сложной, если они таковыми не являются. Наиболее распространенным типом кластера является кластер Beowulf , который представляет собой кластер, реализованный на нескольких идентичных коммерческих готовых компьютерах, соединенных локальной сетью TCP/IP Ethernet . [43] Технология Beowulf была первоначально разработана Томасом Стерлингом и Дональдом Беккером . 87% всех суперкомпьютеров Top500 являются кластерами. [44] Остальные — это процессоры Massively Parallel, описанные ниже.
Поскольку системы сетевых вычислений (описанные ниже) могут легко справляться с неловко параллельными задачами, современные кластеры, как правило, разрабатываются для решения более сложных задач — задач, требующих, чтобы узлы чаще обменивались промежуточными результатами друг с другом. Для этого требуется высокая пропускная способность и, что еще важнее, сеть взаимосвязей с низкой задержкой . Многие исторические и современные суперкомпьютеры используют настраиваемое высокопроизводительное сетевое оборудование, специально разработанное для кластерных вычислений, такое как сеть Cray Gemini. [45] По состоянию на 2014 год большинство современных суперкомпьютеров используют некоторое стандартное сетевое оборудование, часто Myrinet , InfiniBand или Gigabit Ethernet .
Массово-параллельный процессор (MPP) — это один компьютер с множеством сетевых процессоров. MPP имеют много тех же характеристик, что и кластеры, но MPP имеют специализированные сети соединений (тогда как кластеры используют стандартное оборудование для сетей). MPP также, как правило, больше кластеров, обычно имея «гораздо больше» чем 100 процессоров. [46] В MPP «каждый ЦП содержит собственную память и копию операционной системы и приложения. Каждая подсистема взаимодействует с другими через высокоскоростное соединение». [47]
Blue Gene/L от IBM , пятый по скорости суперкомпьютер в мире по данным рейтинга TOP500 за июнь 2009 года , является MPP.
Сетевые вычисления — наиболее распределенная форма параллельных вычислений. Они используют компьютеры, взаимодействующие через Интернет , для работы над заданной проблемой. Из-за низкой пропускной способности и чрезвычайно высокой задержки, доступных в Интернете, распределенные вычисления обычно имеют дело только с неловко параллельными проблемами.
Большинство приложений для сетевых вычислений используют промежуточное программное обеспечение (ПО, которое находится между операционной системой и приложением для управления сетевыми ресурсами и стандартизации программного интерфейса). Наиболее распространенным промежуточным программным обеспечением для сетевых вычислений является Berkeley Open Infrastructure for Network Computing (BOINC). Часто программное обеспечение для добровольных вычислений использует «запасные циклы», выполняя вычисления в то время, когда компьютер простаивает. [48]
Повсеместное распространение Интернета открыло возможность крупномасштабных облачных вычислений.
В параллельных вычислениях существуют специализированные параллельные устройства, которые остаются нишевыми областями интересов. Хотя они не являются специфичными для домена , они, как правило, применимы только к нескольким классам параллельных задач.
Реконфигурируемые вычисления — это использование программируемой пользователем вентильной матрицы (FPGA) в качестве сопроцессора для универсального компьютера. FPGA — это, по сути, компьютерный чип, который может перестраиваться для выполнения заданной задачи.
ПЛИС можно программировать с помощью языков описания оборудования , таких как VHDL [49] или Verilog . [50] Несколько поставщиков создали языки C-HDL , которые пытаются эмулировать синтаксис и семантику языка программирования C , с которым большинство программистов знакомы. Наиболее известными языками C-HDL являются Mitrion-C , Impulse C и Handel-C . Для этой цели также можно использовать определенные подмножества SystemC , основанные на C++.
Решение AMD открыть свою технологию HyperTransport для сторонних поставщиков стало технологией, обеспечивающей высокопроизводительные реконфигурируемые вычисления. [51] По словам Майкла Р. Д'Амура, главного операционного директора DRC Computer Corporation, «когда мы впервые пришли в AMD, они называли нас « ворами сокетов ». Теперь они называют нас своими партнерами». [51]
Универсальные вычисления на графических процессорах (GPGPU) — это сравнительно недавняя тенденция в исследованиях компьютерной инженерии. Графические процессоры — это сопроцессоры, которые были в значительной степени оптимизированы для обработки компьютерной графики . [52] Обработка компьютерной графики — это область, в которой доминируют параллельные операции с данными, в частности, операции с матрицами линейной алгебры .
В ранние дни программы GPGPU использовали обычные графические API для выполнения программ. Однако было создано несколько новых языков программирования и платформ для выполнения вычислений общего назначения на GPU, причем как Nvidia , так и AMD выпустили среды программирования с CUDA и Stream SDK соответственно. Другие языки программирования GPU включают BrookGPU , PeakStream и RapidMind . Nvidia также выпустила специальные продукты для вычислений в своей серии Tesla . Технологический консорциум Khronos Group выпустил спецификацию OpenCL , которая является фреймворком для написания программ, которые выполняются на платформах, состоящих из CPU и GPU. AMD , Apple , Intel , Nvidia и другие поддерживают OpenCL .
Для работы с параллельными приложениями было разработано несколько подходов на основе специализированных интегральных схем (ASIC). [53] [54] [55]
Поскольку ASIC (по определению) специфична для данного приложения, ее можно полностью оптимизировать для этого приложения. В результате для данного приложения ASIC имеет тенденцию превосходить компьютер общего назначения. Однако ASIC создаются с помощью УФ-фотолитографии . Этот процесс требует набора масок, который может быть чрезвычайно дорогим. Набор масок может стоить более миллиона долларов США. [56] (Чем меньше транзисторов, необходимых для чипа, тем дороже будет маска.) Между тем, рост производительности в вычислениях общего назначения с течением времени (как описано законом Мура ) имеет тенденцию сводить на нет эти достижения всего за одно или два поколения чипов. [ 51] Высокая начальная стоимость и тенденция к тому, что вычисления общего назначения, управляемые законом Мура, обгоняют их, сделали ASIC непригодными для большинства приложений параллельных вычислений. Тем не менее, некоторые из них были созданы. Одним из примеров является машина PFLOPS RIKEN MDGRAPE-3 , которая использует пользовательские ASIC для моделирования молекулярной динамики .
Векторный процессор — это центральный процессор или компьютерная система, которая может выполнять одну и ту же инструкцию на больших наборах данных. Векторные процессоры имеют высокоуровневые операции, которые работают с линейными массивами чисел или векторами. Примером векторной операции является A = B × C , где A , B и C — это 64-элементные векторы 64-битных чисел с плавающей точкой . [57] Они тесно связаны с классификацией SIMD Флинна. [57]
Компьютеры Cray стали известны своими векторными процессорами в 1970-х и 1980-х годах. Однако векторные процессоры — как ЦП, так и полноценные компьютерные системы — в целом исчезли. Современные наборы инструкций процессоров включают некоторые инструкции векторной обработки, такие как AltiVec от Freescale Semiconductor и Streaming SIMD Extensions (SSE) от Intel .
Для программирования параллельных компьютеров были созданы параллельные языки программирования , библиотеки , API и модели параллельного программирования (например, алгоритмические скелеты ). Их обычно можно разделить на классы на основе предположений, которые они делают относительно базовой архитектуры памяти — общая память, распределенная память или общая распределенная память. Языки программирования с общей памятью взаимодействуют путем манипулирования переменными общей памяти. Распределенная память использует передачу сообщений . Потоки POSIX и OpenMP являются двумя из наиболее широко используемых API общей памяти, тогда как интерфейс передачи сообщений (MPI) является наиболее широко используемым API системы передачи сообщений. [58] Одной из концепций, используемых при программировании параллельных программ, является концепция будущего , когда одна часть программы обещает доставить требуемые данные другой части программы в некоторое время в будущем.
Усилия по стандартизации параллельного программирования включают открытый стандарт OpenHMPP для гибридного многоядерного параллельного программирования. Модель программирования на основе директив OpenHMPP предлагает синтаксис для эффективной разгрузки вычислений на аппаратных ускорителях и оптимизации перемещения данных в/из аппаратной памяти с использованием удаленных вызовов процедур .
Рост популярности потребительских графических процессоров привел к поддержке вычислительных ядер , как в графических API (называемых вычислительными шейдерами ), так и в специализированных API (таких как OpenCL ) или в других языковых расширениях.
Автоматическое распараллеливание последовательной программы компилятором является «святым Граалем» параллельных вычислений, особенно с вышеупомянутым ограничением частоты процессора. Несмотря на десятилетия работы исследователей компиляторов, автоматическое распараллеливание имело лишь ограниченный успех. [59]
Основные параллельные языки программирования остаются либо явно параллельными , либо (в лучшем случае) частично неявными , в которых программист дает директивы компилятору для распараллеливания. Существует несколько полностью неявных параллельных языков программирования — SISAL , Parallel Haskell , SequenceL , System C (для ПЛИС ), Mitrion-C, VHDL и Verilog .
По мере того, как компьютерная система становится сложнее, среднее время между сбоями обычно уменьшается. Контрольные точки приложений — это метод, при котором компьютерная система делает «моментальный снимок» приложения — запись всех текущих распределений ресурсов и состояний переменных, сродни дампу ядра —; эта информация может быть использована для восстановления программы в случае сбоя компьютера. Контрольные точки приложений означают, что программа должна перезапуститься только с последней контрольной точки, а не с начала. Хотя контрольные точки обеспечивают преимущества в различных ситуациях, они особенно полезны в высокопараллельных системах с большим количеством процессоров, используемых в высокопроизводительных вычислениях . [60]
Поскольку параллельные компьютеры становятся больше и быстрее, мы теперь можем решать проблемы, которые раньше требовали слишком много времени. Такие разные области, как биоинформатика (для сворачивания белков и анализа последовательностей ) и экономика, воспользовались преимуществами параллельных вычислений. Распространенные типы проблем в приложениях параллельных вычислений включают: [61]
Параллельные вычисления также могут применяться для проектирования отказоустойчивых компьютерных систем , в частности, с помощью систем Lockstep, выполняющих одну и ту же операцию параллельно. Это обеспечивает избыточность в случае отказа одного компонента, а также позволяет автоматически обнаруживать и исправлять ошибки , если результаты различаются. Эти методы могут использоваться для предотвращения сбоев из-за единичных событий, вызванных временными ошибками. [63] Хотя во встроенных или специализированных системах могут потребоваться дополнительные меры, этот метод может обеспечить экономически эффективный подход к достижению n-модульной избыточности в коммерческих готовых системах.
Истоки истинного (MIMD) параллелизма восходят к Луиджи Федерико Менабреа и его «Наброску аналитической машины, изобретенной Чарльзом Бэббиджем» . [65] [66] [67]
В 1957 году компания Compagnie des Machines Bull анонсировала первую компьютерную архитектуру, специально разработанную для параллелизма, Gamma 60. [68] Она использовала модель fork-join и «Program Distributor» для отправки и сбора данных в независимые процессоры, подключенные к центральной памяти, и из них. [69] [70]
В апреле 1958 года Стэнли Гилл (Ферранти) обсуждал параллельное программирование и необходимость ветвления и ожидания. [71] Также в 1958 году исследователи IBM Джон Кок и Дэниел Слотник впервые обсудили использование параллелизма в числовых вычислениях. [72] В 1962 году корпорация Burroughs представила D825 — четырехпроцессорный компьютер, который обращался к 16 модулям памяти через перекрестный коммутатор . [73] В 1967 году Амдаль и Слотник опубликовали дискуссию о возможности параллельной обработки на конференции Американской федерации обществ обработки информации. [72] Именно во время этих дебатов был придуман закон Амдаля для определения предела ускорения за счет параллелизма.
В 1969 году Honeywell представила свою первую систему Multics , симметричную многопроцессорную систему, способную запускать до восьми процессоров параллельно. [72] C.mmp , многопроцессорный проект в Университете Карнеги-Меллона в 1970-х годах, был одним из первых многопроцессорных систем с более чем несколькими процессорами. Первым многопроцессорным устройством с шинным подключением и кэшами слежения был Synapse N+1 в 1984 году. [66]
Параллельные компьютеры SIMD можно проследить до 1970-х годов. Мотивацией ранних компьютеров SIMD была амортизация задержки затвора блока управления процессора для нескольких инструкций. [74] В 1964 году Слотник предложил построить массивно параллельный компьютер для Ливерморской национальной лаборатории имени Лоуренса . [72] Его проект финансировался ВВС США , что стало первым проектом параллельных вычислений SIMD, ILLIAC IV . [72] Ключом к его проекту был довольно высокий параллелизм, с 256 процессорами, что позволяло машине работать с большими наборами данных в том, что позже будет известно как векторная обработка . Однако ILLIAC IV называли «самым печально известным из суперкомпьютеров», потому что проект был завершен только на четверть, но занял 11 лет и стоил почти в четыре раза больше первоначальной оценки. [64] Когда в 1976 году он был наконец готов к запуску своего первого реального приложения, его производительность превзошла существующие коммерческие суперкомпьютеры, такие как Cray-1 .
В начале 1970-х годов в Лаборатории компьютерных наук и искусственного интеллекта Массачусетского технологического института Марвин Мински и Сеймур Паперт начали разрабатывать теорию « Общества разума» , которая рассматривает биологический мозг как массивно-параллельный компьютер . В 1986 году Мински опубликовал «Общество разума» , в котором утверждалось, что «разум сформирован из множества маленьких агентов, каждый из которых сам по себе неразумен». [75] Теория пытается объяснить, как то, что мы называем интеллектом, может быть продуктом взаимодействия неразумных частей. Мински говорит, что наибольшим источником идей относительно теории стала его работа по созданию машины, которая использует роботизированную руку, видеокамеру и компьютер для строительства из детских кубиков. [76]
Похожие модели (которые также рассматривают биологический мозг как массивный параллельный компьютер, т.е. мозг состоит из созвездия независимых или полунезависимых агентов) были также описаны:
{{cite book}}
: |website=
проигнорировано ( помощь ){{cite book}}
: CS1 maint: несколько имен: список авторов ( ссылка )Все моделируемые схемы были описаны на языке описания оборудования (VHDL) сверхбыстрой интегральной схемы (VHSIC). Аппаратное моделирование было выполнено на Xilinx FPGA Artix 7 xc7a200tfbg484-2.
Однако святой Грааль таких исследований — автоматическое распараллеливание последовательных программ — еще не материализовался. Хотя автоматическое распараллеливание определенных классов алгоритмов было продемонстрировано, такой успех в значительной степени был ограничен научными и числовыми приложениями с предсказуемым управлением потоком (например, вложенные структуры циклов со статически определенными числами итераций) и статически анализируемыми шаблонами доступа к памяти. (например, обходы больших многомерных массивов данных с плавающей точкой).