Ответы пользователя по тегу Параллельные вычисления
  • Есть ли смысл учитывать аппаратное количество потоков в игровом движке?

    @nirvimel
    Пул потоков по умолчанию содержит число потоков, равное количеству ядер аппаратных потоков. У этого пула есть входная очередь (lock-free), куда сабмитятся поступающие таски. Когда CPU недонагружен очередь пустая. Когда все потоки заняты, очередь растет.

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

    Кстати, очередь задач на пуле потоков - это именно то, как многозадачность реализуется внутри ОС. Только тут сами потоки ОС являются тасками, которые ставятся в очередь. Разница в производительности объясняется тем, что переключение тасков в юзерспейсе легче (следовательно быстрей), чем переключение потоков ОС.
    Ответ написан
    2 комментария
  • Какие книги почитать по параллельному программированию на Scala?

    @nirvimel
    Параллельно программирование в основном касается рантайма, а не собственно языка.
    Поэтому, можно брать всю ту же литературу, что и для параллельного программирование на Java (а такой литературы достаточно). Принципы там одни, да и библиотеки в основном пересекаются. Другой язык никак не помешает пользоваться общим рантаймом. Единственное отличие: на Scala аналогичный код в итоге может выглядеть намного красивее (если при написании мыслить по-скаловски).
    Впоследствии стоит переходить к изучению документация к специфическим скалавским параллельным библиотекам/фреймворкам (Akka и др.). На более продвинутом уровне чтение исходников стандартной и сторонних библиотек будет давать гораздо более информации за более короткое время, а чтение книг (авторы которых просто пропустили через свою голову прочитанный код) покажется расточительным расходованием своего времени.

    Рецепт изучения (один из возможных): Если начинать с самых азов, то подойдет соответствующая глава (про concurrency) из книги Брюса Эккеля. Там дается очень неплохое введение в тему, раскрываются соответствующие данной области проблемы и показываются основные пути их решения.
    Далее следует выбрать более конкретное направление. В рамках темы параллельных вычислений существуют несколько различных подходов (смешивать их в одном проекте не только бессмысленно, но и опасно).
    1. Классический подход, основанный на потоках и блокировках ресурсов.
    1A. Разновидность (1), где вместо явных блокировок используются неблокирующие очереди.
    2. Подход, основанный на повсеместном использовании Promise/Future.
    3. Акторы (типизированные и нетипизированные (эти почему-то становятся более популярны)).
    4. STM.
    После выбора подхода к решению распараллеливания вычислений, следует выбрать конкретный инструмент (библиотеку) и углубится в изучение его официальной документации и любых примеров, найденных в Сети. На более продвинутом уровне можно будет перейти к чтению исходников и сторонняя литература больше не понадобится.

    UPD: Все-таки существует специальная книга по Scala Concurrecy. Я ее не читал. Но судя по оглавлению, все основные темы там раскрываются.
    Ответ написан
    Комментировать
  • Почему Python multiprocessing нестабилен?

    @nirvimel
    Хорошо, что вы указали в тегах Windows, это все объясняет. Под Windows нет простого способа "раздвоиться" процессу при вызове multiprocessing.Process, поэтому осуществляется очень сложная эмуляция этого поведения. При этом функция target выдирается из модуля, запускается в отдельном интерпретаторе, а все параметры сереализуются передаются и десереализуются перед вызовом target, при этом инициализация модуля в новом интерпретаторе выполняется частично (инициализируется только глобальный контекс). Подробнее об этом, например, тут, есть еще одна очень хорошая статья где подробно рассмотрен этот механизм, но сейчас не найду ссылку.

    Коротко о том, как готовить multiprocessing под Windows:
    1. Разделять процессы (вызов multiprocessing.Process()) как можно раньше в коде.
    2. По возможности избегать инициализации любых ресурсов и глобальных переменных до разделения. Учитывайте, что этот код выполняется во всех процессах независимо и может давать кучу сторонних эффектов.
    3. Не передавать через args никаких сложных объектов с "поведением" (кроме объектов из самого multiprocessing, он сам знает как их правильно передавать), только голые данные (примитивы или объекты состоящие только из примитивов), которые сериализуются без сторонних эффектов.
    4. Создавать дочерние процессы один раз, и на протяжении всего времени работать с ними посредством обмена сообщениями через Pipe/Queue. Не порождать новые процессы в цикле вычислений в момент "когда понадобятся".
    5. Queue при попытке записи/чтения может блокировать процесс, если при этом происходит запись/чтения в/из нее в другом процессе. (Думаю, именно это и происходит в коде в вопросе).
    6. Лучше использовать Pipe, который в худшем случае блокирует один процесс, а не все, как Queue.
    7. При создании процесса можно передавать ему два Pipe (input одного + output другого), в вызывающем процессе хранить соответствующие им коннекторы и только при помощи их общаться с дочерним процессом.
    8. Можно не делать process.join(), а просто читать результаты из output Pipe, они прочтутся только после того как попадут туда, что дальше будет происходить с процессом уже не важно (можно поставить return после записи в Pipe в дочернем процессе).
    Ответ написан
    4 комментария
  • Как реализованы параллельные вычисления в многоядерных процессорах?

    @nirvimel
    Многоядерность сама по себе никак не связана с вычислительным конвейером. На каждом ядре свой конвейер и его работа не зависит от других ядер.

    Суть многоядерности в том, что каждое ядро выполняет свой вычислительный поток. На N-ядерном процессоре в каждый момент времени параллельно выполняются N потоков.

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