Дядя Дима (ddima) wrote,
Дядя Дима
ddima

Category:

Многопоточность (поток сознания)

Что-то я много стал писать про тренд, надо бы достать из закромов заготовки, сделанные раньше. Вот например, пост, драфт которого был написан по итогам встречи с Интелом около месяца назад. Все никак не доходили руки довести текст до ума. На самом деле идея не нова, но я пока не знаю вменяемых разработок и описательных средств, которые бы позволяли эффективно параллелить приложение.

Модная несколько лет назад тема "а давайте разместим игровой цикл в двух потоках - графика отдельно, физика отдельно" постепенно сходит на нет. И слава богу. По целому ряду причин. Во-первых, двухпроцессорными машинами уже никого не удивить, скоро никто не будет удивляться процессорам, в которых количество ядер будет измеряться двузначными числами. А во-вторых (и это более важно), ручное распределение задач по ядрам имеет определенную степень осмысленности только для простых задач, где такое распределение действительно может принести определенный перформанс. Но чем сложнее становится код, тем сложнее: а) держать в голове все выполняемые приложением задачи, б) иметь действительно эффективную реализацию многопоточности, в которой треды будут выполнять вычисления, а не ожидать друг друга.

При дальнейшем усложнении приложения можно получить и совсем дурацкую ситуацию - вручную распараллеленное приложение будет работать медленнее, чем точно такое же, но выполняемое в один поток. Ситуация сродни программированию на асемблере - известно, что ручной ассемблерной реализацией на синтетическом примере можно "выжать" еще 10-15% производительности из кода против С. Но если писать большую программу на ассемблере, то это займет гигантское количество времени и ресурсов, а результат вряд ли будет производительнее, чем высокоуровневая программа.
То же самое происходит и здесь. Ручное распараллеливание синтетического примера действительно может дать хороший прирост производительности. Ручное распараллеливание крупной программы почти наверняка потребует гигантских усилий и может принести замедление вместо ожидаемого ускорения.

OpenMP далеко не панацея. Если говорить про паралеллизацию внутри рассчетных функций, то накладные расходы на вход в параллельный расчет могут перекрывать весь буст. Да и в зависимости от структуры кода и специфики вычислений далеко не факт, что удастся найти достаточное количество мест, где применить параллелизацию. Если использовать OpenMP с внутренними функциональными вызовами, то надо хорошо представлять себе, какие вызовы и ручные синхронизации надо засовывать во вложенные функции. Фактически, получаем тот же самое ручное распараллеливание, разница только в том, что N тредов созданы заранее (накладные расходы на CreateThread высоки), они спят на эвенте, и включаются, как только есть openmp scope. По окончании засыпают снова. ТВВ тоже не панацея - это почти то же самое распределение задач, чуть более автоматизированное, которое заставляет держать программиста в голове огромное количество данных про выполняемые задачи, используемые подсистемы и т.п.

Попробуем расширить концепцию многопоточности (это будет очень похоже на PS3, но никто нам не запрещает расширить "сферу применения"). В первую очередь надо абстрагироваться от того, что у нас один многоядерный комп. Пусть лучше будет много одноядерных. Их "общая память" (в смысле, если это один многоядерный комп) - это определенный бонус, но даже если это разные компьютеры со связью по TCP/IP - это не так страшно. Если компьютеров много, то и параллельные вычисления, и распределенные вычисления, и мультиплеер - все они хорошо ложатся под это определение.

Что меняется, если принять такой концепт? Меняется подход к организации вычислений. Каждый "компьютер" (или тред) выполняют задачи. Отдельная задача имеет:
  • входные параметры.
  • выходные данные.
  • константные данные, которые могут требоваться в процессе вычислений.
Вход и выход может приходить по TCP/IP или браться из оперативной памяти. С константными данными - все еще проще - они могут закешироваться на локальном компьютере (если это распределенные вычисления) или даже полностью безопасно браться из общей памяти (на одном многоядерном компьютере).

Задачи именованные, каждая {категория} задач имеет собственное описание, которое позволяет определить следующее:
  • порядок исполнения задач (либо с помощью приоритетов, либо с помощью dependencies before/after, как это было реализовано в RedKey).
  • использование константных и неконстантных внешних данных. Константные внешние данные могут безопасно использоваться любым количеством задач, неконстантные определяют последовательность выполняемых операций. Очевидно, что менеджер должен заниматься правильной "укладкой" задач в конвеер.
  • использование (эксклюзивное, и не очень) внешнего middleware, ресурсов компьютера и т.п.
Фактически проблему хочется свести к тому, что конкретный программист реализует задачи, исполняемые (с точки зрения взаимодействия с внешними данными) в однопоточной среде. Количество объектов синхронизации в основных задачах при этом сводится к нулю, в используемых библиотеках (если они не thread safe)  и в самом менеджере синхронизация, ессно, остается.

Что получаем в качестве бонуса:
  • действующие приложения - это один большой "task: do all".
  • возможность гибко параллелизовать исполняемую программу либо на любое количество процессоров, либо на любое количество компьютеров в "облаке" (разумеется, при достаточно распределенной системе задач и гибких связях).
  • возможность реализовывать runtime профилирование и оптимизацию задач с точки зрения наиболее грамотного распределения их по ядрам (с учетом замеряемого времени выполнения), за счет информации об используемых данных - оптимизировать доступы в память (в многопроцессорной машине - для использования константных данных для максимального количества задач ежесекундно, в облаке - для минимизации кешей и пересылок на компьютерах).
  • возможность отлаживать программу специальными перемешиваниями задач - для контроля правильности описания.
  • И многое многое другое.
Что за язык будет описывать такую систему - я пока не знаю, если кто знает - поделитесь ссылками. Придуманная связка language + external definitions работают не очень хорошо и требуют завидной аккуратности. Нужно, чтобы система задач была интегрирована в сам язык. Ключевым описанием в котором становится не function/procedure foo(), а task do_something с описаниями зависимостей и взаимосвязей.
Tags: prog
Subscribe

  • .

    Я никуда не пропал, но последнее время меня можно найти только за городом (все выходные + отпуск, из которого на 3 дня вышел на работу :) ).

  • Тренд и текущее

    По результатам майской расчистки участка в ночь с 1 на 10 число: насколько я понимаю, смысл жизни среднестатистического советского дачника заключался…

  • Строительство, и ни капли agile'а

    Вот оно, чего я так долго планировал сам, продумывал, рисовал в Google SketchUp, и наконец, вопротил в жизнь при помощи профессиональных…

  • Post a new comment

    Error

    Comments allowed for friends only

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 41 comments
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →

  • .

    Я никуда не пропал, но последнее время меня можно найти только за городом (все выходные + отпуск, из которого на 3 дня вышел на работу :) ).

  • Тренд и текущее

    По результатам майской расчистки участка в ночь с 1 на 10 число: насколько я понимаю, смысл жизни среднестатистического советского дачника заключался…

  • Строительство, и ни капли agile'а

    Вот оно, чего я так долго планировал сам, продумывал, рисовал в Google SketchUp, и наконец, вопротил в жизнь при помощи профессиональных…