Совет относительно запуска большого многопоточного проекта программирования

Моя компания в настоящее время запускает стороннюю программу моделирования (моделирование риска природной катастрофы), который сосет выше на гигабайты данных от диска и затем уплотняет в течение нескольких дней для приведения к результатам. Меня скоро попросят переписать это как многопоточное приложение так, чтобы оно работало в течение многих часов вместо дней. Я ожидаю иметь приблизительно 6 месяцев для завершения преобразования и буду работать соло.

У нас есть 24-proc поле для выполнения этого. У меня будет доступ к источнику исходной программы (записанный в C++, я думаю), но в этой точке я знаю очень мало о том, как это разработано.

Мне нужен совет относительно того, как заняться этим. Я - опытный программист (~ 30 лет, в настоящее время работающих в C# 3.5), но не имею никакого опыта мультипроцессора / многопоточного опыта. Я желаю и стремлюсь выучить новый язык при необходимости. Я ищу рекомендации на языках, изучая ресурсы, книги, архитектурные инструкции. и т.д.

Требования: Windows OS. Компилятор товарного сорта с большой поддержкой и хорошими доступными ресурсами изучения. Нет никакой потребности в необычном GUI - он будет, вероятно, работать из файла конфигурации и помещать результаты в базу данных SQL Server.

Править: Текущим приложением является C++, но я не буду почти наверняка использовать тот язык для переписывания. Я удалил тег C++, который кто-то добавил.

11
задан ire_and_curses 16 November 2011 в 17:12
поделиться

16 ответов

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

В высокопроизводительных вычислениях обычно проводятся симуляции. распараллелил с использованием либо MPI , либо OpenMP . MPI - это библиотека передачи сообщений с привязками для многих языков, включая C, C ++, Фортран , Python и C # . OpenMP - это API для многопроцессорной обработки с общей памятью. В общем, MPI сложнее кодировать, чем OpenMP, и он гораздо более агрессивен, но при этом гораздо более гибок. OpenMP требует, чтобы область памяти разделялась между процессорами, поэтому он не подходит для многих архитектур. Гибридные схемы также возможны.

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

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

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

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

Превосходный онлайн-обзор параллельных вычислений, охватывающий основные проблемы, - это введение из Ливерморской национальной лаборатории Лаверенса .

17
ответ дан 3 December 2019 в 00:54
поделиться

Я не делаю ' Не знаю, упоминалось ли об этом еще, но если бы я был на вашем месте, то, что я делал бы прямо сейчас (помимо чтения каждого размещенного здесь ответа), писал бы пример многопоточного приложения на вашем любимом (наиболее часто используемом) языке.

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

Я желаю вам удачи в этом начинании и должен признать, что хотел бы иметь возможность работать над чем-то вроде этого ...

0
ответ дан 3 December 2019 в 00:54
поделиться

Если возможно, чтобы все потоки работали с непересекающимися наборами данных процесса, а другая информация хранилась в базе данных SQL, вы можете довольно легко сделать это на C ++ и просто порождать новые потоки для работы над своими частями с помощью Windows API. SQL-сервер будет обрабатывать всю магию жесткой синхронизации с транзакциями БД! И, конечно же, C ++ будет работать намного быстрее, чем C #.

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

0
ответ дан 3 December 2019 в 00:54
поделиться

Здесь можно дать множество конкретных индивидуальных советов, и несколько человек уже сделали это. Однако никто не может сказать вам, как именно заставить все это работать в соответствии с вашими конкретными требованиями (которые вы еще даже не знаете полностью), поэтому я настоятельно рекомендую вам прочитать HPC (High Performance Computing) сейчас, чтобы прояснить общие концепции и лучше понять, какое направление больше всего соответствует вашим потребностям.

2
ответ дан 3 December 2019 в 00:54
поделиться

Если вы можете разделить рабочую нагрузку на независимые части работы (т. Е. Набор данных может обрабатываться в битах, нет большого количества зависимостей данных), тогда я бы использовать пул потоков / механизм задач. Предположительно все, что есть в C # как эквивалент Java java.util.concurrent. Я бы создал рабочие единицы из данных и заключил их в задачу, а затем перебросил задачи в пул потоков.

Конечно, здесь может потребоваться производительность. Если вы можете оставить исходное ядро ​​кода обработки как есть, то вы можете вызвать его из своего приложения C #.

Если код имеет много зависимостей данных, его может быть намного сложнее разбить на многопоточные задачи, но вы могли бы разбить его на последовательность действий. Это означает, что поток 1 передает данные потоку 2, который передает данные потокам с 3 по 8,

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

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

Кроме того, разделение данных и действий на более мелкие части делает приложение намного проще в обслуживании и тестировании.

2
ответ дан 3 December 2019 в 00:54
поделиться

Модель, которую вы выберете, будет определяться структурой ваших данных. Ваши данные сильно или слабо связаны? Если ваши данные моделирования тесно связаны, вам стоит взглянуть на OpenMP или MPI (параллельные вычисления). Если ваши данные слабо связаны, то, вероятно, лучше подойдет пул заданий ... возможно, даже подход распределенных вычислений может работать.

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

Книга "Искусство параллелизма: нитевидная обезьяна", которая работает как введение в эту тему, получила довольно высокую оценку.

2
ответ дан 3 December 2019 в 00:54
поделиться

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

Отладка условий гонки явно неприятна.

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

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

12
ответ дан 3 December 2019 в 00:54
поделиться

Для 6-месячного проекта я бы сказал, что он определенно окупается сначала начните читать хорошую книгу на эту тему. Я бы предложил Параллельное программирование Джо Даффи в Windows . Это самая полная книга, которую я знаю по этому вопросу, и она охватывает как .NET, так и нативную потоковую передачу Win32. Я писал многопоточные программы в течение 10 лет, когда обнаружил этот драгоценный камень, и все еще находил вещи, которых не знал почти в каждой главе.

Кроме того, «моделирование риска природных катастроф» звучит как много математики. Возможно, вам стоит взглянуть на библиотеку Intel IPP: она предоставляет примитивы для многих распространенных низкоуровневых математических алгоритмов и алгоритмов обработки сигналов. Он поддерживает многопоточность прямо из коробки, что может значительно облегчить вашу задачу.

3
ответ дан 3 December 2019 в 00:54
поделиться

Вы пометили этот вопрос как C ++, но упомянули, что вы C # разработчик в настоящее время, поэтому я не уверен, будете ли вы выполнять это задание с C ++ или C #. В любом случае, если вы собираетесь использовать C # или .NET (включая C ++ / CLI): у меня есть следующая статья MSDN, отмеченная закладкой, и я настоятельно рекомендую прочитать ее как часть вашей подготовительной работы.

Асинхронный вызов синхронных методов

0
ответ дан 3 December 2019 в 00:54
поделиться

Какая бы технология вы ни собирались написать это, взгляните a необходимо прочитать книгу по параллелизму «Параллельное программирование на Java» , а для .Net я настоятельно рекомендую библиотеку retlang для параллельного приложения.

0
ответ дан 3 December 2019 в 00:54
поделиться

Я бы подумал о том, чтобы сделать это в .NET 4.0, так как он имеет много новой поддержки, специально предназначенной для облегчения написания параллельного кода. Его официальная дата выпуска - 22 марта 2010 г., но, вероятно, до этого времени он будет RTM, и теперь вы можете начать с достаточно стабильной бета-версии 2.

Вы можете использовать либо C #, с которым вы более знакомы, либо управляемый C ++ .

На высоком уровне попробуйте разбить программу на System.Threading.Tasks.Task , которые представляют собой отдельные единицы работы. Кроме того, я бы минимизировал использование общего состояния и рассмотрел возможность использования Parallel.For (или ForEach ) и / или PLINQ , где это возможно.

Если Если вы это сделаете, большая часть тяжелой работы будет сделана за вас очень эффективно. Это' - направление, которое Microsoft будет все больше поддерживать.

2 : Я бы подумал о том, чтобы сделать это в .NET 4.0, поскольку он имеет много новой поддержки, специально предназначенной для облегчения написания параллельного кода. Его официальная дата выпуска - 22 марта 2010 года, но, вероятно, до этого времени будет RTM, и вы можете начать с достаточно стабильной Beta 2 уже сейчас. На высоком уровне попробуйте разбить программу на System.Threading.Tasks.Task , которые представляют собой отдельные единицы работы. Кроме того, я бы минимизировал использование общего состояния и рассмотрел возможность использования Parallel.For и / или PLINQ, где это возможно. Если вы сделаете это, большая часть тяжелой работы будет сделана за вас очень эффективно. 1 : http://msdn.microsoft.com/en-us/library/dd321424%28VS.100%29. aspx

1
ответ дан 3 December 2019 в 00:54
поделиться

Прочтите об Erlang и, в частности, «Модель актера». Если вы сделаете все свои данные неизменяемыми, вам будет намного проще распараллелить их.

2
ответ дан 3 December 2019 в 00:54
поделиться

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

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

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

Я бы добавил одну вещь, если вы Если мы намерены остаться с C ++, мы добились большого успеха, используя библиотеку boost .thread. Он предоставляет большинство необходимых многопоточных примитивов, хотя и не имеет пула потоков (и я бы опасался неофициального пула потоков "boost", который можно найти через Google, потому что он страдает рядом проблем с взаимоблокировкой).

1
ответ дан 3 December 2019 в 00:54
поделиться

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

Вы находитесь в ограниченном времени. Срок - 6 месяцев, и вы даже не знаете наверняка, на каком языке эта система, что она делает и как устроена. Если это нетривиальное вычисление, то это очень плохое начало.

Самое главное: вы говорите, что никогда раньше не занимались многопоточным программированием. Здесь у меня звонят сразу 4 будильника. Многопоточность сложна и требует много времени, чтобы изучить ее, когда вы хотите сделать это правильно - и вам нужно делать это правильно, когда вы хотите добиться огромного увеличения скорости. Отладка чрезвычайно неприятна даже с использованием хороших инструментов, таких как отладчик Total Views или Intel VTune.

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

Но изучение многопоточности и нового языка (каковы ваши навыки C ++?) С сроком в 3 месяца (вы должны написать одноразовый прототип - поэтому я сократил временной промежуток на две половины) - чрезвычайно сложная задача.

Мой совет здесь прост, и он мне не понравится: изучите многопоточность сейчас - потому что это необходимый набор навыков в будущем - но оставьте эту работу тому, у кого уже есть опыт. Хорошо, если вы не заботитесь об успехе программы и просто ищете 6-месячный платеж.

Но изучение многопоточности и нового языка (каковы ваши навыки C ++?) С графиком в 3 месяца (вам нужно написать одноразовый прототип - поэтому я сократил временной интервал на две половины) чрезвычайно сложно.

Мой совет здесь прост, и он мне не понравится: изучите многопоточность сейчас - потому что это необходимый набор навыков в будущем - но оставьте эту работу тому, у кого уже есть опыт. Хорошо, если вы не заботитесь об успехе программы и просто ищете 6-месячный платеж.

Но изучение многопоточности и нового языка (каковы ваши навыки C ++?) С графиком в 3 месяца (вам нужно написать одноразовый прототип - поэтому я сократил временной интервал на две половины) чрезвычайно сложно.

Мой совет здесь прост, и он мне не понравится: изучите многопоточность сейчас - потому что это необходимый набор навыков в будущем - но оставьте эту работу тому, у кого уже есть опыт. Хорошо, если вы не заботитесь об успехе программы и просто ищете 6-месячный платеж.

Изучите многопоточность сейчас - потому что это необходимый набор навыков в будущем - но оставьте эту работу тому, у кого уже есть опыт. Хорошо, если вы не заботитесь об успехе программы и просто ищете 6-месячный платеж.

Изучите многопоточность сейчас - потому что это необходимый набор навыков в будущем - но оставьте эту работу тому, у кого уже есть опыт. Хорошо, если вы не заботитесь об успехе программы и просто ищете 6-месячный платеж.

1
ответ дан 3 December 2019 в 00:54
поделиться

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

Самый общий и универсальный - просто «избегать разделяемого состояния». По возможности копируйте ресурсы между потоками, а не заставляйте их обращаться к одной и той же общей копии.

Если вы сами пишете низкоуровневый код синхронизации, вы должны помнить, что не должны делать абсолютно никаких предположений. И компилятор, и ЦП могут переупорядочивать ваш код, создавая условия гонки или тупиковые ситуации, когда при чтении кода это невозможно. Единственный способ предотвратить это - использовать барьеры памяти. И помните, что даже простейшая операция может вызвать проблемы с потоками. Такие простые вещи, как ++ i , обычно не являются атомарными, и если доступ к i осуществляется несколькими потоками, вы И, конечно же, только потому, что вы присвоили значение переменной, это не гарантирует, что новое значение будет видно другим потокам. Компилятор может отложить фактическую запись его в память. Опять же, барьер памяти вынуждает его «сбрасывать» все ожидающие операции ввода-вывода.

Если бы я был на вашем месте, я бы использовал модель синхронизации более высокого уровня, чем простые блокировки / мьютексы / мониторы / критические разделы, если это возможно. Есть несколько библиотек CSP , доступных для большинства языков и платформ, включая языки .NET и собственный C ++.

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

Другой подход может быть Транзакционная память . Его легче вписать в традиционную структуру программы, но он имеет некоторые ограничения, и я не знаю многих библиотек для него (STM.NET был недавно выпущен, и, возможно, стоит его проверить. У Intel есть C ++ компилятор с расширениями STM, также встроенными в язык)

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

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

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

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

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

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

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

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