~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ C922DBC0F6B06081090B453B82AB1054__1714598820 ✰
Заголовок документа оригинал.:
✰ Loop-level parallelism - Wikipedia ✰
Заголовок документа перевод.:
✰ Параллелизм на уровне цикла — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Loop-level_parallelism ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/c9/54/c922dbc0f6b06081090b453b82ab1054.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/c9/54/c922dbc0f6b06081090b453b82ab1054__translat.html ✰
Дата и время сохранения документа:
✰ 22.06.2024 17:39:33 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 2 May 2024, at 00:27 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Параллелизм на уровне цикла — Википедия Jump to content

Параллелизм на уровне цикла

Из Википедии, бесплатной энциклопедии

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

Описание [ править ]

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

Пример [ править ]

Рассмотрим следующий код, работающий со списком L длины n.

для   (  int   я   знак равно   0  ;   я   <   п  ;   ++  я  )   { 
     S1  :   L  [  я  ]   +=   10  ; 
  } 

Каждая итерация цикла берет значение из текущего индекса Lи увеличивает его на 10. Оператор If S1 берет T время выполнения, то цикл занимает время n * Tвыполняться последовательно, игнорируя время, затрачиваемое конструкциями цикла. Теперь рассмотрим систему с p процессоры, где p > n. Если n потоки выполняются параллельно, время выполнения всех n шагов сводится к T.

Менее простые случаи приводят к непоследовательным, то есть несериализуемым результатам. Рассмотрим следующий цикл, работающий с тем же списком L.

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   L  [  я  ]   знак равно   L  [  я  -1  ]   +   10  ; 
  } 

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

Зависимости в коде [ править ]

В коде можно найти несколько типов зависимостей. [1] [2]

Тип Обозначения Описание
Истинная (поточная) зависимость S1 ->T S2 Истинная зависимость между S1 и S2 означает, что S1 записывает в место, которое позже будет прочитано S2.
Антизависимость S1 ->A S2 Антизависимость между S1 и S2 означает, что S1 читает из места, куда позже запишет S2.
Выходная зависимость S1 ->O S2 Зависимость вывода между S1 и S2 означает, что S1 и S2 записывают в одно и то же место.
Входная зависимость S1 ->I S2 Входная зависимость между S1 и S2 означает, что S1 и S2 считывают из одного и того же места.

Чтобы сохранить последовательное поведение цикла при параллельном запуске, необходимо сохранить истинную зависимость. С антизависимостью и зависимостью от выпуска можно справиться, предоставив каждому процессу собственную копию переменных (так называемая приватизация). [1]

Пример истинной зависимости [ править ]

S1  :   int   a  ,   b  ; 
  S2  :   а   =   2  ; 
  S3  :   б   =   а   +   40  ; 

S2 ->T S3, что означает, что S2 действительно зависит от S3, поскольку S2 записывает в переменную a, из которого читает S3.

Пример борьбы с зависимостью [ править ]

S1  :   int   a  ,   b   =   40  ; 
  S2  :   а   =   б   -   38  ; 
  S3  :   б   =   -1  ; 

S2 ->A S3, что означает, что S2 не зависит от S3, поскольку S2 читает переменную b прежде чем S3 напишет в него.

Пример зависимости от вывода [ править ]

S1  :   int   a  ,   b   =   40  ; 
  S2  :   а   =   б   -   38  ; 
  S3  :   а   =   2  ; 

S2 ->O S3, что означает, что S2 имеет выходную зависимость от S3, поскольку оба записывают в переменную a.

Пример зависимости от ввода [ править ]

S1  :   int   а  ,   б  ,   с знак   равно   2  ; 
  S2  :   а   =   с   -   1  ; 
  S3  :   б   =   с   +   1  ; 

S2 ->I S3Это означает, что S2 имеет входную зависимость от S3, поскольку S2 и S3 оба читают из переменной c.

Зависимость в циклах [ править ]

Зависимость, переносимая в цикле, и зависимость, независимая цикла от

Циклы могут иметь два типа зависимости:

  • Циклическая зависимость
  • Независимая от цикла зависимость

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

В следующем примере кода, используемого для обмена значениями двух массивов длины n, существует независимая от цикла зависимость S1 ->T S3.

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   tmp знак   равно   а  [  я  ]; 
      S2  :   а  [  я  ]   =   б  [  я  ]; 
      S3  :   б  [  я  ]   =   tmp  ; 
  } 

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

Пример циклической зависимости, где S1[i] ->T S1[i + 1], где i указывает текущую итерацию, а i + 1 указывает на следующую итерацию.

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   а  [  я  -1  ]   +   1  ; 
  } 

График зависимости, передаваемый по циклу [ править ]

График зависимостей, переносимых циклом, графически показывает зависимости, переносимые циклом, между итерациями. Каждая итерация отображается как узел на графике, а направленные ребра показывают истинные, анти- и выходные зависимости между каждой итерацией.

Типы [ править ]

Существует множество методологий распараллеливания циклов.

  • РАСПРЕДЕЛЕННЫЙ цикл
  • ДОЛЛ Параллелизм
  • ДОАКРОСС Параллелизм
  • СПИРАЛЬ [3]
  • ДОПИП Параллельность

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

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

Тип Описание
Разложение Программа разбита на задачи — наименьшую единицу параллелизма, которую можно использовать.
Назначение Задачи назначаются процессам.
оркестровка Доступ к данным, связь и синхронизация процессов.
Картирование Процессы привязаны к процессорам.

РАСПРЕДЕЛЕННЫЙ цикл [ править ]

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

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   а  [  я  -1  ]   +   б  [  я  ]; 
      S2  :   c  [  я  ]   +=   d  [  я  ]; 
  } 

Цикл имеет зависимость, переносимую циклом S1[i] ->T S1[i+1] но S2 и S1 не имеют зависимости, независимой от цикла, поэтому мы можем переписать код следующим образом.

цикл1  :   for   (  int   я   знак равно   1  ;   я   <   n  ;   ++  я  )   { 
     S1  :   а  [  я  ]   =   а  [  я  -1  ]   +   б  [  я  ]; 
  } 
 Loop2  :   for   (  int   i   =   1  ;   я   <   n  ;   ++  я  )   { 
     S2  :   c  [  я  ]   +=   d  [  я  ]; 
  } 

Обратите внимание, что теперь цикл 1 и цикл 2 могут выполняться параллельно. Вместо того, чтобы одна инструкция выполнялась параллельно с разными данными, как при параллелизме на уровне данных, здесь разные циклы выполняют разные задачи с разными данными. Допустим, время выполнения S1 и S2 будет и тогда время выполнения последовательной формы приведенного выше кода равно , Теперь, поскольку мы разделили два оператора и поместили их в два разных цикла, мы получаем время выполнения . Мы называем этот тип параллелизма либо параллелизмом функций, либо параллелизмом задач.

DOALL-параллелизм [ править ]

Параллелизм DOALL существует, когда операторы внутри цикла могут выполняться независимо (ситуации, когда нет зависимости, переносимой циклом). [1] Например, следующий код не читает из массива aи не обновляет массивы b, c. Ни одна итерация не зависит от какой-либо другой итерации.

для   (  int   я   знак равно   0  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   б  [  я  ]   +   c  [  я  ]; 
  } 

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

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

начать_параллелизм  (); 
  для   (  int   я   знак равно   0  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   б  [  я  ]   +   c  [  я  ]; 
      конец_параллелизм  (); 
  } 
 блокировать  (); 

DOACROSS-параллелизм [ править ]

DOACROSS Параллелизм существует, когда итерации цикла распараллеливаются путем извлечения вычислений, которые могут выполняться независимо, и их одновременного выполнения. [5]

Синхронизация существует для обеспечения зависимости, передаваемой по циклу.

Рассмотрим следующий синхронный цикл с зависимостью S1[i] ->T S1[i+1].

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     а  [  я  ]   знак равно   а  [  я  -1  ]   +   б  [  я  ]   +   1  ; 
  } 

Каждая итерация цикла выполняет два действия.

  • Рассчитать a[i-1] + b[i] + 1
  • Присвойте значение a[i]

Расчет стоимости a[i-1] + b[i] + 1, и тогда выполнение присваивания можно разложить на две строки (операторы S1 и S2):

S1  :   int   tmp   знак равно   б  [  я  ]   +   1  ; 
  S2  :   а  [  я  ]   =   а  [  я  -1  ]   +   tmp  ; 

Первая линия, int tmp = b[i] + 1;, не имеет зависимости от цикла. Затем цикл можно распараллелить, параллельно вычислив значение temp, а затем синхронизировав назначение с a[i].

сообщение  (  0  ); 
  для   (  int   я знак   равно   1  ;   я   <   n  ;   ++  я  )   { 

     S1  :   int   tmp знак   равно   б  [  я  ]   +   1  ; 
      подождите  (  я  -1  ); 

      S2  :   а  [  я  ]   =   а  [  я  -1  ]   +   tmp  ; 
      пост  (  я  ); 
  } 

Допустим, время выполнения S1 и S2 будет и тогда время выполнения последовательной формы приведенного выше кода равно , Теперь, поскольку существует параллелизм DOACROSS, ускорения можно достичь за счет выполнения итераций в конвейерном режиме, что дает нам время выполнения .

DOPIPE-параллелизм [ править ]

DOPIPE Parallelism реализует конвейерный параллелизм для зависимости, переносимой циклом, где итерация цикла распределяется по нескольким синхронизированным циклам. [1] Цель DOPIPE — действовать как сборочный конвейер, на котором один этап запускается, как только для него имеется достаточно данных с предыдущего этапа. [6]

Рассмотрим следующий синхронный код с зависимостью S1[i] ->T S1[i+1].

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   а  [  я  -1  ]   +   б  [  я  ]; 
      S2  :   c  [  я  ]   +=   а  [  я  ]; 
  } 

S1 должен выполняться последовательно, но S2 не имеет зависимости от цикла. S2 может выполняться параллельно с использованием параллелизма DOALL после последовательного выполнения всех вычислений, необходимых для S1. Однако в этом случае ускорение будет ограничено. Лучшим подходом является распараллеливание таким образом, чтобы S2, соответствующий каждому S1, выполнялся после завершения указанного S1.

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

для   (  int   я   знак равно   1  ;   я   <   п  ;   ++  я  )   { 
     S1  :   а  [  я  ]   знак равно   а  [  я  -1  ]   +   б  [  я  ]; 
          пост  (  я  ); 
  } 

 for   (  int   я   знак равно   1  ;   я   <   n  ;   я  ++  )   { 
         подождите  (  я  ); 
      S2  :   c  [  я  ]   +=   а  [  я  ]; 
  } 

Допустим, время выполнения S1 и S2 будет и тогда время выполнения последовательной формы приведенного выше кода равно , Теперь, поскольку существует параллелизм DOPIPE, ускорения можно достичь за счет выполнения итераций в конвейерном режиме, что дает нам время выполнения , где p — количество параллельно работающих процессоров.

См. также [ править ]

Ссылки [ править ]

  1. ^ Перейти обратно: а б с д Это Солихин, Ян (2016). Основы параллельной архитектуры . Бока-Ратон, Флорида: CRC Press. ISBN  978-1-4822-1118-4 .
  2. ^ Гофф, Джина (1991). «Практическое тестирование на зависимость». Материалы конференции ACM SIGPLAN 1991 года по проектированию и реализации языков программирования — PLDI '91 . стр. 15–29. дои : 10.1145/113445.113448 . ISBN  0897914287 . S2CID   2357293 .
  3. ^ Мерфи, Найл. «Обнаружение и использование параллелизма в циклах DOACROSS» (PDF) . Кембриджский университет . Проверено 10 сентября 2016 г.
  4. ^ Кави, Кришна. «Распараллеливание циклов DOALL и DOACROSS — исследование» . {{cite journal}}: Для цитирования журнала требуется |journal= ( помощь )
  5. ^ Унникришнан, Прия (2012), «Практический подход к распараллеливанию DOACROSS», Параллельная обработка Euro-Par 2012 , Конспекты лекций по информатике, том. 7484, стр. 219–231, номер документа : 10.1007/978-3-642-32820-6_23 , ISBN.  978-3-642-32819-0 , S2CID   18571258
  6. ^ «DoPipe: эффективный подход к распараллеливанию моделирования» (PDF) . Интел . Проверено 13 сентября 2016 г.
Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: C922DBC0F6B06081090B453B82AB1054__1714598820
URL1:https://en.wikipedia.org/wiki/Loop-level_parallelism
Заголовок, (Title) документа по адресу, URL1:
Loop-level parallelism - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)