Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет dibr ([info]dibr)
@ 2009-10-10 17:51:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
lazy life

     Disclaimer: описанное ниже - не чисто техническое, но и литературное произведение. Поэтому технической строгости не требуйте - что-то "в реальности" может быть не реализовано или реализовано по другому. Но хочется верить, что всё описанное - как минимум реализуемо :-)

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

       (c) ibash

     Вообще, у компьютерщиков постоянно так. Чтобы программу с одной стороны не переписывать заново (и не сильно утруждать себя лишними мыслями при написании), а с другой стороны - чтобы оно работало "ещё быстрее", есть два стандартных способа: использовать "ленивое (отложенное) что-то" (самый известный пример - "отложенная запись" в дисковом кеше), или наоборот - "упреждающее что-то" (упреждающее чтение в нём же). В первом случае, когда нужно совершить какое-то действие, программе сообщают "да сделано уже, сделано" (а сделают потом, когда время будет, или когда реально понадобится), во втором - наоборот, делают какое-то действие заранее, на всякий случай - авось понадобится. Кстати, хороший пример второго подхода - упреждающее выполнение операций процессором. Процессор запускает на выполнение операции, для которых ещё не получены операнды, в надежде что когда операцию фактически начнут выполнять - операнд уже приедет - и это работает! Правда, операции иногда приходится выполнять по нескольку раз, пока не приедет операнд :-) Кстати, интересная статья, почитайте.
     Когда-то давно на тему "отложенного чего-то" я прикалывался, мол, если есть отложенная запись - давайте сделаем отложенное (не "упреждающее", а именно отложенное) чтение. Скажем программе, что то что она хотела прочитать - прочиталось, а прочитаем как-нибудь потом. Тогда я думал, что это прикол. Сейчас понял - это вполне реально: мы просто пометим (в менеджере виртуальной памяти) эти страницы памяти как "лежащие во-он там на диске", и как только приложение полезет с ними реально работать - произойдёт экспешн, управление будет передано куда-надо, и мы быстренько дочитаем их на ходу, прозрачно для приложения :-) При том что приложение не факт что сразу полезет работать со считанным, и тем более не факт что использует всё считанное - может и правда получиться ускорение. Правда, такое вроде бы нигде не реализовано, ограничились memory mapped files, что близко по смыслу, но не так смешно по названию :-)

     А теперь вот - "ленивые вычисления".
     Идея-то простая. Программист сказал - "посчитай мне, сколько будет логарифм тангенса пи на четыре, и положи в переменную Икс", программа сказала "ага". Программист сказал - "ну и что же у нас оказалось в Икс?", программа - "ой, ё... счас посчитаю" - и считает :-) Реализовано может быть по разному - через "встроенные свойства языка", через те же экспешны, через какие-нибудь особые объекты с автоматически активирующимся методом "а теперь подсчитать уже в самом деле" при обращении к каким-то его частям, или ещё как-нибудь.
     Польза номер раз - если программист попросил заполнить массив логарифмами тангенсов углов от 0 до 2*пи с шагом 0.001*пи, а потом пользуется всего десятком элементов, заранее неизвестно каких - то остальные элементы считать в общем-то необязательно. То же самое реализуется "кешированием результатов вычислений", но отложенные вычисления будут прозрачнее с точки зрения программиста, а в данном случае - скорее всего ещё и быстрее.
     Польза номер два интереснее. Скажем, наша программа имеет два массива - с электрическим и с магнитным полем. И рассчитывает, по кругу, одно из другого - моделирует, тсзть, эволюцию полей во времени. Для расчета электрического поля - магнитное должно быть полностью подсчитано (все используемые значения должны быть из одного "момента виртуального времени"), в программе это, ясное дело, реализуется тем что считается один массив, потом второй, потом опять первый, второй... Распараллелить это можно - считаем один массив, а в соседнем потоке, с небольшим оставанием по индексу элемента - считаем второй. Но сразу же возникнет геморрой с синхронизацией, чтобы второй поток не забежал вперёд и не стал использовать "ещё не посчитанные" (старые) данные первого массива... в-общем, "типичный физик", пишущий программу сам, про синхронизацию знающий что это когда "где-то в системе то-ли семафоры ставят, то-ли стрелки переводят", и искренне верящий что spinlock, malloc и maalox - однокоренные слова, с таким точно не справится.
     А теперь давайте так. "А вычисли-ка мне первый массив" - "А легко!". "А теперь второй, но при вычислении понадобятся данные из первого" - и при (фактическом) вычислении второго массива, при первом же обращении к элементам первого массива, начнётся вычисление элементов первого масива. Идущее, ясное дело, "с упреждением" - пока не досчитан нужный элемент, не разблокируется вычисление для второго массива, но которые вычисления можно, что характерно, пустить параллельным потоком. А значит в результате мы совершенно на халяву, то есть даром, сделали из однопоточной программы - двухпоточную, не изменив её "логику" с точки зрения программиста.
     Но это ещё не всё. Обсчёт массивов ведь повторяется в цикле, 1-2-1-2-1-2, и так 10000 раз. Если у нас будет возможность делать вложенные ленивые вычисления нужной глубины - то фактический расчет можно будет откладывать на N шагов. И, скажем, на 8-ядерном компьютере, делая вложенные "ленивые вычисления", и форсируя фактический обсчёт каждые 8 шагов, мы автоматом нагрузим все восемь ядер. При этом алгоритм на вид останется совершенно линейным, без каких-то признаков распараллеленности.
     А если не форсировать обсчёт ручками, то фактический обсчёт произойдёт только тогда, когда данные понадобятся в явном виде - например, чтобы сохранить их в файл. Лишь бы памяти хватило, всю лабуду связанную с "отложенностью" хранить.

     Но с другой стороны - зачем так себя ограничивать? Оба модных нынче направления, и объектно-озабоченное, считающее что "всё - объект", и дофигаразрядное, считающее что http://google.com, не говоря уже о каких-то там локальных файлах, должно просто маппиться куда-то в адресное пространство, не делают принципиального различия между "файлом" и "областью памяти": "память / диск, мальчик / девочка - какая разница"? Это либо "объект", либо "один фиг имеет адрес".
     А значит, и в файл в принципе можно сохранить "ленивые" данные. Просто, ну, пометить их, что если в самом деле понадобятся - то их можно подсчитать, вон и программа есть. Получится специальный, "ленивый", файл - точнее, "ленивая" область в файле.

     Но уж когда результат расчёта будет вставлен в презентацию - уж тогда-то точно потребуется подсчитать уже на самом деле?
     Да, в-общем, необязательно. Программы давно умеют и "вставлять ссылки" (показывая на их месте специальные иконки - мол, тут объект, но отрисую я его когда меня попросят), и разделять "превьюшную" и "окончательную" форму отображения - при редактировании показывать "упрощённую" картинку (мол, "тут - график"), и только при окончательной отрисовке - вытягивать объект целиком и просить его отрисоваться.

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

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

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


(Добавить комментарий)


[info]mikell@lj
2009-10-10 11:26 (ссылка)
Вот большое тебе спасибо - за объяснение "на пальцах". Наконец то я понял, ЗАЧЕМ это надо.

Похожее ощущение было, когда я вдумчиво курил API для win95, напоролся на memory mapped files, и понял как же винда запускает программы и dll...

(Ответить) (Ветвь дискуссии)


[info]dibr@lj
2009-10-10 11:40 (ссылка)
Предупреждаю: в вышенаписанном заметная часть - мои фантазии, не фактическое положение дел. И не только начиная с записи в файл, но и выше :-)
То есть, понимание - это здорово, но мануалы если что всё равно понадобятся.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]mikell@lj
2009-10-10 12:00 (ссылка)
Само собой, но вот это *понимание* - дорогого стоит.

(Ответить) (Уровень выше)


[info]yorool_gui@lj
2009-10-10 12:30 (ссылка)
И ты написал все это ни разу не подумав слово "хаскель"? Не верю!

(Ответить) (Ветвь дискуссии)


[info]dibr@lj
2009-10-10 12:44 (ссылка)
Я ж не программист. А это - не статья по IT, а беллетристика, от фр. belles lettres — «изящная словесность».

А знать про хаскель, эрланг, вар'ак, или систему команд OISC (http://en.wikipedia.org/wiki/One_instruction_set_computer)-процессора - беллетристу необязательно :-)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alpha_cygnus@lj
2009-10-12 11:19 (ссылка)
Хорошая беллетристика, кстати, показывает некое правильное понимание ленивости. А для тех, кто в теме Хаскель сам лезет в каждой строчке :-)

(Ответить) (Уровень выше)


[info]ilya_314@lj
2009-10-10 19:39 (ссылка)
Вот ты как знающий хаскель может пояснишь. Там как я понимаю есть ленивые вычисления и соответственно в процессе выполнения могут параллелиться эти самые ленивые вычисления. Возникают ли при этом стандартные проблемы с паралельностью типа взаимных блокировок, неатомарное изменение состояния объъекта и пр., т.е. решает ли хаскель хотя бы частично проблемы многопоточного программирования?

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]yorool_gui@lj
2009-10-11 05:15 (ссылка)
Там с этим все не так просто. Вот тут в комментах ссылка есть на доклад по этой проблеме:
http://yorool-gui.livejournal.com/183605.html?thread=654389#t654389
А на данный момент все надо самому паралеллить - треды в зубы и пошел.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]unreal_undead@lj
2009-10-12 04:38 (ссылка)
Причём, я так понимаю, это некий "откат назад" - по сравнению с parallel haskell (не glasgow, a MITовским - http://csg.csail.mit.edu/projects/languages/ph.shtml ) и его lenient calculations.

(Ответить) (Уровень выше)


[info]alpha_cygnus@lj
2009-10-12 06:59 (ссылка)
Многие проблемы многопоточности решаются не столько ленивостью, сколько отсутствием изменяемых данных, а в хаскеле неизменяемость возведена в абсолют, который следует из ленивости (в том смысле, что допустить изменения в данных и скрестить с повсеместными ленивыми вычислениями, то будет непредсказуемый ужас).
А ленивость часто считается хороша тем, чтоб в ней легко представимы бесконечные структуры данных, ибо каждое выражение - это всего лишь намерение что-то посчитать, точнее - способ, но считать до бесконечности обычно никто не заставляет.
Но в посте алгоритм параллелится именно ленивостью, только вот, говорят, автомагически это не очень получается, ибо Хаскель параллелится вообще на всём и выгода от параллельности губится количеством процессов.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ilya_314@lj
2009-10-12 11:02 (ссылка)
>в хаскеле неизменяемость возведена в абсолют

Следует ли из этого, что там в принципе нельзя спровоцировать конфликт с изменением данных? Например я использую ссылку на один массив в двух местах - среда исполнения гарантирует, что одновременно изменять один элемент мне не дадут? Это работает на уровне элементарных типов? Если так, то достигается это видимо путем глобального обвешивания объектов блокировками, что вобщем решает проблему на уровне элементарных типов хоть и тормозит изрядно.

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

Поэтому применимость ленивых вычислений как мне кажется довольно узкоспециализировано и видимо никак не решает проблемы многопоточности. Тут (http://ru.wikipedia.org/wiki/Ленивые_вычисления) вобщем параллельность не упоминается.

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

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alpha_cygnus@lj
2009-10-12 11:13 (ссылка)
Так, повторюсь в двух пунктах.
а) Я не знаю точно, как может помочь в распараллеливании ленивость, но в распараллеливании точно помогает принципиальное отсутствие изменения данных. Вообще.
б) В Хаскеле данные НЕ МЕНЯЮТСЯ. Есть видимость изменения, которая достигается копированием (в особо тяжёлых случаях). Но это на концептуальном уровне. За счет ленивости расписать что там реально происходит не совсем тривиальная задача.
За счёт отсутствия изменяемости блокировки просто не нужны. Очень близко к этому понятие "чистоты". То есть, функция возвращает всегда одно и то же значение, если были переданы одни и те же аргументы. (В монадах есть неявный аргумент, который протаскивается через цепочку связанных функций и со стороны это выглядит изменяемым состоянием).
Соответственно, как считать и в каком порядке значения таких функций глубоко по фигу, а значит их можно без проблем распараллелить, если они не связаны, а все связи явны и выражаются на уровне передачи значений одной функции в другую - вот это уже параллельно не посчитаешь.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ilya_314@lj
2009-10-12 11:44 (ссылка)
> а) Я не знаю точно, как может помочь в распараллеливании ленивость, но в распараллеливании точно помогает принципиальное отсутствие изменения данных.

Это понятно, вопрос про особенности Хаскеля.

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

В целом ленивые вычисления в части распараллеливания алгоритмов никаких чудесных результатов не дадут.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]alpha_cygnus@lj
2009-10-12 12:01 (ссылка)
Ну в общем, да.
Но распараллеливать, не применяя локов, можно без лени. См. Erlang, он не ленивый, но изменяемых данных в нём тоже почти нет. И локов нет. Зато есть миллионы тредов.
А Хаскель хорош тем, что в нём многие экспериментальные вещи можно выразить красиво. Вот и выражают. Например, Software Transactional Memory (STM). СТМ можно не только в Хаскеле сделать, но Х. хорош тем, что там работа с STM за счёт языка чётко выделяется на фоне остальных вычислений.

(Ответить) (Уровень выше)


[info]ilya_314@lj
2009-10-10 19:40 (ссылка)
Да еще вопрос. Приведи какие-нибудь примеры применения ленивых вычислений. Я так думаю как раз для распараллеливания полезная штука должна быть и соответственно заменять собой классический подход в лоб.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]yorool_gui@lj
2009-10-11 05:34 (ссылка)
Так вот Дима привел уже - про два массива, где первый зависит от второго а второй от первого. В хаскеле можно это как есть, так и написать и не париться с ручным управлением, в каком порядке все считать.

А так вот классический пример - вычисление чисел фибонначи:

ghci> let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

fibs - это ленивый список. Вычисляться он будет, только если попросят. Например так:

ghci> take 10 fibs
[0,1,1,2,3,5,8,13,21,34]

zipWith - функция, которая как бы застегивает два списка (2 и 3-й параметры) на застежку-молнию. Роль замка выполняет первый параметр zipWith - функция двух аргументов, в данном случае (+). Результат - новый список, полученный применением этой функции к попарно взятым элементам списков.
Легко видеть, что без ленивых вычислений такое не написать.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dibr@lj
2009-10-11 06:13 (ссылка)
> Так вот Дима привел уже - про два массива, где первый зависит от второго а второй от первого.

Замечу, я сам не уверен, что мой пример корректен. Поскольку "второй" зависит от "первого", но от "второго" зависит не "первый", а новое значение "первого". То есть, в каком порядке считать - задано алгоритмом, ленивые вычисления в моём примере смогут разве что дать "параллельность нахаляву", и никаких других бонусов. Учитывая вот это:

> А на данный момент все надо самому паралеллить - треды в зубы и пошел.

...вопрос к тебе: мой пример - корректен, или пока всё-таки фантастичен?

> А так вот классический пример - вычисление чисел фибонначи:

Классическая проблема классических примеров - совершенно неочевидно, где они могут встретиться в реальности :-)
А числа фибоначчи как-то ведь считали и до ленивых вычислений, и даже оптимизировали многократный счёт - кешированием результатов, например. Да, код получится либо менее оптимальный (с рекурсией) либо более сложный (с кешированием), но революционность ленивых вычислений из примера не очень очевидна. То есть, пример понятный, но какой-то, эээ, академический :-)

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dmit_lj@lj
2009-10-16 05:33 (ссылка)
У меня сильные сомнения в том, что "параллельность нахаляву" будет иметь место.

Вот у нас при вычислении второго массива выяснилось, что надо сначала посчитать значение из первого. Да, мы их можем считать в другом потоке (на другом ядре), но что при этом будет делать тот поток, который считал второй массив? А ждать он будет. Так что вычисления получатся последовательными.

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

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dibr@lj
2009-10-16 05:49 (ссылка)
Практически, как я понял - да, с параллельностью тут пока всё туго, лучше использовать специально предназначенные для этого средства, типа openMP.

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

А считать один массив в два потока - это только ручками, поскольку там есть "перекрёстные" (нелокальные) зависимости, и их придётся явным образом разрешать...

(Ответить) (Уровень выше)


[info]malykh@lj
2009-10-10 13:01 (ссылка)
По поводу первого, сразу вспомнилась старинная реализация (точнее эмуляция) memory mapped files в OS/2: http://www.edm2.com/0610/memorymap.html Один в один. ;-)

Остальное не осилил, сорри. Но нутром чую, что там функциональщиной пахнет.

(Ответить) (Ветвь дискуссии)


[info]dibr@lj
2009-10-10 13:17 (ссылка)
"Стройная система костылей и подпорок", ага :-)

А и пусть пахнет. Если оно не мешает жить, и при этом способно иногда приносить пользу - то что в этом плохого?

(Ответить) (Уровень выше)


[info]vikky_13@lj
2009-10-11 06:10 (ссылка)
Не знаю, насколько ты в курсе, но современные компилаторы продвинуты настолько, что онии не просто выкидывают из программы расчет переменной, которая нигде дальше не использутеся, но и могут сделать это даже в некоторых более сложных случаях, например, если у нас вычисляется А, потом В(А), а потом В нигде не используется. Тогда не считаются ни А ни В.
Про вынос вычислений одного массива в отдельный поток _без ведома программиста_ - вопрос очень неоднозначный. Во многих случаях это производительность только испортит (например, если и без того потоков достаточно, или, если упреждение расчета подобрать неправильно (а подобрать его правильно, чтобы не ждать понапрасну - тоже нетривиально)
В этом отношении мне очень нравится OpenMP-она тоже "сохраняет" линейный алгоритм.

(Ответить) (Ветвь дискуссии)


[info]dibr@lj
2009-10-11 06:36 (ссылка)
> Тогда не считаются ни А ни В.

С точки зрения компилятора, если я сделал printf("%d",x[i]) - я использовал массив x, и его расчет выкинуть нельзя. Можно было бы выкинуть расчёт неиспользуемых элементов, но компилятор заранее не знает, чему будет равно i, и выкинуть не может.
С точки зрения ленивых вычислений - расчёт сразу не делается вообще. Но когда понадобится x[13] - считается x[13], и отдаётся куда надо.

> Про вынос вычислений одного массива в отдельный поток _без ведома программиста_ - вопрос очень неоднозначный.

С ведомом, с ведомом :-) Более того - хорошо бы ещё "с возможностью принудительного указания". Поскольку вычисление может содержать взаимодействие с окружающим миром (чтение/запись файлов, прочий ввод-вывод), компилятор не может знать насколько эти побочные эффекты критичны, поэтому по умолчанию вроде бы должен делать это "безотлагательно". Но если _программист_ уверен, что это безопасно - пусть позволит компилятору делать ленивые вычисления и с такими функциями :-)

> Во многих случаях это производительность только испортит (например, если и без того потоков достаточно

Ну, для любой технологии можно придумать место, где она всё испортит :-) Скажем, на C# не очень удобно писать прошивки для однокристалльных микроконтроллеров, а на ассемблере - сложно написать веб-браузер :-)
А вот у нас на работе стоит сейчас четырёхядерная хрень. И мы не знаем, что с этими ядрами делать, поскольку алгоритмы - как у меня в примере: теоретически параллелятся, но практически - геморрой не стоит свеч. Был бы компилятор с поддержкой ленивых вычислений - загрузили бы сейчас все четыре ядра :-)

> если упреждение расчета подобрать неправильно (а подобрать его правильно, чтобы не ждать понапрасну - тоже нетривиально)

Ну, почему нетривиально? "Размер нелокальности" в этой конкретной задаче известен (+-1 элемент), задаём "упреждение", скажем, 10 элементов, и имеем следующее. Расчёт второго массива обращается к элементу первого. Расчёт второго блокируется (за отсутвием элемента), запускается расчёт первого. Расчёт считает требуемый элемент _и ещё 10 следующих_. Расчёт второго разблокируется сразу после расчета первого элемента первого массива, и дальше 9 шагов расчёты идут "плечом к плечу". Затем расчёт второго обращается к 11-му элементу первого, и всё повторяется. А можно и без цифр - обращение к элементу первого массива запускает счёт первого массива, и он тупо весь считается. Если обсчёт первого обогнал обсчет второго - всё нормально. Если отстал - обсчёт второго будет иногда блокироваться "по отсутствию элемента".

> В этом отношении мне очень нравится OpenMP-она тоже "сохраняет" линейный алгоритм.

А кстати, есть где-нибудь популярное изложение? Там, как я понимаю, главный вопрос - разобраться с зависимостями, в частности мой пример "с двумя массивами" вроде бы не распараллелится?

(Ответить) (Уровень выше) (Ветвь дискуссии)

automatic parallelization
[info]ajojo@lj
2009-10-11 16:21 (ссылка)
А это счетная задача? На Фортране писаная? Просто у многих современных компиляторов в native есть флажок "а параллелизуй-ка мне, дорогой компилятор, все те вычисления, которые параллелизации с твоей точки зрения поддаются".
В частности, пиаря родную контору, пока она еще не до конца съедена оракулем, ;-) могу сказать, что в SunStudio compilers есть флажок "-xautopar". У Интеля разумеется тоже есть какой-то функциональный аналог этого, но имени его я не знаю. Только в бесплатности Интеля я не уверен.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: automatic parallelization
[info]dibr@lj
2009-10-12 15:44 (ссылка)
Счётная, писаная на сях :-) Правда, с интерфейсом на не самом новом borland c builder'е, и убедить программиста перетащить счётный код подо что-то другое будет нелегко.

Другой вопрос, что подозреваю что автоматическое распараллеливание не факт что поможет: не уверен, что компилятор сможет сам распараллелить вычисление первого и второго массива (ведь второй массив использует первый, а это само по себе означает "запрет" на распараллеливание), а распараллеливание в пределах одного массива - требует явных алгоритмических усилий по "сшивке" раздельно считаемых частей массива.
В-общем, малой кровью не обойдёшься :-) Впрочем, мне тут уже вспомнили про OpenMP - может быть он в самом деле поможет :-)

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: automatic parallelization
[info]ajojo@lj
2009-10-13 06:48 (ссылка)
Ну, с - это тоже неплохо. :-) Фронтенды существуют для c/c++/fortran. Но если к этому уже прикручен (и крепко) интерфейс - тогда о-па! Потому что компилятор, про который я говорю, только под юниксы. Впрочем даже оставаясь на виндах (icc&gcc), интерфейсную часть все равно надо будет отдирать, если она завязана на bc. Если остро хотеть использовать все процессоры, конечно. ;-)
А OMP вещь хорошая, только вот знающие коллеги утверждают, что начиная только с версии три. К тому же, и это довольно ожидаемо, сложные вещи на OMP делать... сложно, а с простыми скорее всего и автоматический параллелизатор справится. Впрочем, попробовать никто не мешает.
Хотя всегда остается вопрос а окупится ли весь этот геморрой. ;-)

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: automatic parallelization
[info]ilya_314@lj
2009-10-13 07:07 (ссылка)
На моем опыте - openmp из vs2005 очень неплохо работает. Возможности openmp не безграничны и контроль на низком уровне недостаточен, но для рассчетных задач это и не нужно, не игру же какую-нибудь пишут.

В автоматические параллелизаторы что-то не верится, все равно нужно сперва алгоритм подготовить. Например в цикле идут рассчеты, есть некоторые пересечения по данным. Как автомат защитит от взаимовлияния на пересекающихся данных? Даже если он попытается их обойти, то получится неэффективно потому как алгоритм не готов к распараллеливанию. Если же дизайн уже подготовлен к этому, то достаточно расставить блокировки и критические секции и указать что надо параллелить - это и позволяет делать openmp без углубления в детали.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: automatic parallelization
[info]ajojo@lj
2009-10-13 12:00 (ссылка)
Работает, никто ж не спорит. Кстати, vs2005 - это два с половиной?
Что же до не верится, то ответ тут только один - надо взять и проверить. ;-) Благо, санстудия раздается бесплатно. На относительно простых (алгоритмически) счетных примерах, хотя мы не знаем насколько простой пример у Дмитрия, действительно можно сказать "-xautopar" и не заморачиваться. То есть, это проверялось. Разумеется, если есть какие-то неочевидные зависимости по данным, то параллелизатор будет вести себя максимально консервативно. Да, если у нас алгоритм именно такой, то с помощью OMP компилятору можно подсказать, что вот тут - "безопасно" и получить выигрыш. Однако, "Если же дизайн уже подготовлен к этому..." - то и OMP уже не нужно. В этом, собственно, и point.

Кстати, поскольку компилятор достаточно разговорчивый, то его можно попросить рассказать о том, почему он не стал параллелить какой-то кусок. И посмотреть на этот кусок внимательнее. ;-) Это уже к вопросу о подготовке.

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: automatic parallelization
[info]ilya_314@lj
2009-10-13 12:15 (ссылка)
В vs2005 - openmp 2.0 и в vs2008 аналогично.

Да, попробовать можно на каком-нибудь небольшом примере. Потому как портировать крупный кусок в другой компилятор как правило без проблем не получается. Интересен был бы такой результат - если код "правильно" с точки зрения компилятора подготовлен, то тогда получаем производительность близкую к openmp.

Оглядываясь назад я вижу, что многие вещи не зная процессов внутри приложения надо железно запрещать в параллельности, т.е. "безопасному" варианту почти ничего будет параллелить.

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

(Ответить) (Уровень выше)


[info]ilya_314@lj
2009-10-11 17:03 (ссылка)
По поводу того, что вам надо параллелить что-то там на работе для четырехядерника. Скажу на примере своей работы. Появились двухядерники и вскоре четырехядерники, нужно было минимальными усилиями распараллелить самые критичные алгоритмы. В нашем случае openmp оказался идеальным решением. Начиная с 2005-ой студии c/с++ поддерживает openmp, использовать его предельно просто - в нужных местах ставятся #pragma, которые указывают что и как параллелить (для реализации хитрых блокировок еще есть спец. объект), включаешь ключик компилятора и все работает. Никакого понятия нити и управления этими ресурсами не требуется. Буквально за несколько дней некоторые вещи распараллелили и при этом масштабирование делается автоматически, максимальное число используемых нитей можно задать произвольно. Вот простейший пример для неких абстрактных алгоритмов:

// изолируем контекстные данные алгоритмов, которые надо выполнить параллельно
vector<Algo> v;

// все что внутри будет параллельно выполнено
#pragma omp parallel
for(int i = 0; i < v.size(); ++v)
{
v[i].run();
}

Но конечно всякие конфликты по доступу к данным остаются на совсести программиста, где-то пришлось блокировку делать, где-то ставится #pragma omp critiacal, но в целом если все изолировано то просто элементарно делается.

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

http://msdn.microsoft.com/ru-ru/library/dd335940.aspx
http://software.intel.com/ru-ru/articles/getting-started-with-openmp/
http://software.intel.com/en-us/articles/advanced-openmp-programming/
http://software.intel.com/ru-ru/articles/more-work-sharing-with-openmp/
http://rsdn.ru/article/cpp/32_OpenMP_traps.xml
http://msdn.microsoft.com/ru-ru/library/tt15eb9t.aspx

Если что спрашивай, поделюсь тем что знаю.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dibr@lj
2009-10-12 15:46 (ссылка)
Спасибо, на досуге почитаю :-)
Главной проблемой скорее всего окажется проблема перетаскивания программиста под соответствующую VS. Сейчас используется какой-то древний BCB, и интерфейсная часть, как это часто бывает, сильно "вросла" в код. А под VS придётся её переделывать...

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]ilya_314@lj
2009-10-12 16:12 (ссылка)
Это может быть серьезной проблемой. Я бы посоветовал тогда считалку сделать консольной и выделить в отдельный процесс.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dibr@lj
2009-10-12 16:14 (ссылка)
Я идею вброшу (программа не моя), а там уж посмотрим, будет ли энтузиазм. Переписывать скорее всего придётся заметное количество кода...

(Ответить) (Уровень выше)


[info]ilya_314@lj
2009-10-12 16:13 (ссылка)
Вобщем не обязательно консольной, главное что отдельно.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]dibr@lj
2009-10-12 16:15 (ссылка)
Я, кстати, по причинам исторического плана, считаю в консольном приложении :-) Но мне проще, у меня двумерных массивов нет, и потребности в их визуализации тоже...

(Ответить) (Уровень выше)

Оффтопик
[info]dibr@lj
2009-10-12 16:13 (ссылка)
А кстати. Я правильно помню, основным объективом у тебя сейчас EF-S 17-85?

(Ответить) (Уровень выше) (Ветвь дискуссии)

Re: Оффтопик
[info]ilya_314@lj
2009-10-12 16:25 (ссылка)
Да, такой как у тебя.

(Ответить) (Уровень выше)


[info]demon_nn@lj
2009-10-12 06:45 (ссылка)
До сохранения в файл - очень напоминает работу компилятора :) Чесслово. Так оно и есть. Он, зараза такой, читает программу, строит граф вычислений, а потом, по требуемому на volatile результату разворачивает вычисления в зад и строит для них программу.

Однако да printf("%d", x[i]) он может и не "развернуть"... Хотя многое зависит от того, что, где и как написано.

А еще это сильно напоминает работу DirectX и вообще всей современной графики. Тама параллельность жуткая, да до куче еще и на отдельном девайсе. В результате весь DX работает приблизительно таким образом:
Посчитай 1! - Есть.
Теперь 2 из 1! - Готово.
Теперь 3 из 2! - Сделано Сэр.
Хорошо, теперь покажи это на экране! - Ой... Подождите малость... Я тут еще 1 досчитываю...

Там правда не совсем ленивость. Скорее просто параллельность. Но сильно похоже.
А с ленивыми вычислениями может такая засада оказаться. Результат нужен "внезапно", а его еще и нету... Ну типа, показать ту презенташку с графиком, а его, график, два дня на данном ноуте считать нада.

(Ответить)


[info]yorool_gui@lj
2009-10-15 04:14 (ссылка)
Про параллельность и треды я соврал. Сейчас все лучше:
http://donsbot.wordpress.com/2009/09/05/defun-2009-multicore-programming-in-haskell-now/

(Ответить)