Набрёл на довольно интересный пост, спорный конечно, но основная мысль даже не вынесенная в заголовок, а в том, что архитектура фон Неймана — не единственная возможная схема, но на неё завязаны большинство современных языков программирования.
Но возникает вопрос — а что можно противопоставить им? Какие языки будут хорошо ложиться на архитектуру Cell?
(в статье приводится Erlang, насколько он подходит не берусь утверджать, а с другой стороны 1 язык это маловато)
Здравствуйте, Курилка, Вы писали:
К>Набрёл на довольно интересный пост, спорный конечно, но основная мысль даже не вынесенная в заголовок, а в том, что архитектура фон Неймана — не единственная возможная схема, но на неё завязаны большинство современных языков программирования. К>Но возникает вопрос — а что можно противопоставить им? Какие языки будут хорошо ложиться на архитектуру Cell? К>(в статье приводится Erlang, насколько он подходит не берусь утверджать, а с другой стороны 1 язык это маловато)
Я так часто слышал мнения, что архитектура фон Неймана (которую правдолюбы называют все же архитектурой фон Цузе) плоха, что стал в этом сомневаться.
Вот крамольный вопрос: так ли она плоха?
И каковы пределы роста эффективности за счет распараллеливания? Ведь есть такие ограничители, связанные с самой задачей, как, например, "критический путь".
Вот, навскидку, три источника роста производительности:
1) более эффективные алгоритмы;
2) распараллеливание;
3) конвейеризация (для потока однотипных задач; наподобие конвейеризации в RISC-процессорах).
И в чем их принципиально ограничивает архитектура фон Неймана?
Предполагаю, что проблема не в ней, а в ограничениях роста, связанных с алгоритмами.
Другой миф (IMHO) — о каких-то небывалых преимуществах функционального программирования перед императивным.
Может быть, я и правда ретроград, но использование АТД и классов кажется мне вполне естественным, удобным и эффективным, а ограничение себя одними функциями — нет.
Не так давно на RSDN обсуждалась статья Вирта в недавнем номере IEEE Computer.
Там он назвал потенциальную распараллеливаемость, свойственную функциональным языкам, "маргинальным преимуществом".
Это вызвало возмущение.
Но Вирт указал причину, по которой он считает это преимущество маргинальным. На его взгляд активные объекты (владеющие собственым потоком) еще лучше, нет надобности переходить на функциональные языки.
Конечно, все высказанное — сугубое IMHO.
Но мне (лично) кажется несколько нездоровым, что на RSDN такой популярностью пользуются:
1) фантастика (функциональное программирование);
2) чрезмерное увлечение мелкими деталями кодирования, взгляд "с высоты птичьего помета". Достаточно сослаться на огромное число форумов, посвященных, по сути, кодированию на Си++. До сих пор идут бои местного значения в форуме "Плохой язык C++".
Как мне кажется, этим два пунктам, могущих интересовать юношей, уделяется чрезмерное внимание.
Что указывают на некоторую незрелость наших обсуждений.
Все это, повторюсь, IMHO, и не следует мое ворчание принимать чрезмерно всерьез или на свой счет.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>Другой миф (IMHO) — о каких-то небывалых преимуществах функционального программирования перед императивным.
нет здесь такого мифа
AVC>Но Вирт указал причину, по которой он считает это преимущество маргинальным. На его взгляд активные объекты (владеющие собственым потоком) еще лучше, нет надобности переходить на функциональные языки.
Каким образом эти самые активные объекты могут помочь распараллеливать задачу? Давай рассмотрим это на примере задачи умножения матриц.
AVC>1) фантастика (функциональное программирование);
фантастика — это то, чем занимается сам Вирт. А на функциональных языках пишут вполне даже production системы.
Здравствуйте, Дарней, Вы писали:
Д>Каким образом эти самые активные объекты могут помочь распараллеливать задачу? Давай рассмотрим это на примере задачи умножения матриц.
Умножение матриц и есть AVC> взгляд "с высоты птичьего помета".
Вы ещё про сортировку и поиск вспомните...
Активные объекты — это элементы архитектуры программы, т.е. это из области крупномасштабного программирования. Они решают общую задачу преобразования информации. Информация получается, обрабатывается и выдаётся разными объектами асинхронно.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Умножение матриц и есть AVC>> взгляд "с высоты птичьего помета". СГ>Вы ещё про сортировку и поиск вспомните...
можно ещё вспомнить про потоковое кодирование/декодирование данных, рендеринг изображений. Это как раз те задачи, где распараллеливание действительно востребовано.
А как распараллеливать задачи, где распараллеливание не особо то и нужно — это мало кого интересует. Кроме Вирта, конечно.
СГ>Активные объекты — это элементы архитектуры программы, т.е. это из области крупномасштабного программирования. Они решают общую задачу преобразования информации. Информация получается, обрабатывается и выдаётся разными объектами асинхронно.
На таком уровне задача прекрасно решается на C#, Java, Erlang, С++ и многих других языках. И даже не надо ни менять ОС, ни переписывать всю программу на оберон.
Здравствуйте, minorlogic, Вы писали:
M>Попытался представить распаралеленый рендеринг изображения на функциональном языке...
не вижу здесь приципиальных проблем, кроме (возможно) некоторого снижения эффективности вычислений. Но это всё равно будет компенсироваться общим ускорением за счет разделения по процессорам.
А ты видишь?
minorlogic,
M>Попытался представить распаралеленый рендеринг изображения на функциональном языке...
Не стоит перенапрягать своё воображение.
render_spawn(1) ->
ok.
render_spawn(N) when is_integer(N) ->
spawn(render_module, render, []),
render_spawn(N - 1).
% в модуле render_module
render() ->
% чего-то тут рендерим...
ok.
Здравствуйте, Дарней, Вы писали:
Д>можно ещё вспомнить про потоковое кодирование/декодирование данных, рендеринг изображений. Это как раз те задачи, где распараллеливание действительно востребовано.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Там востребована аппаратная реализация: графические акселераторы, аппаратные кодеры/декодеры,...
чтобы выпускать новое железо каждый раз, когда обновляется версия кодека?
СГ>Совершенно на ровном месте, ни с того ни с сего вдруг Вирту и Оберону за что-то досталось... При чём тут они?
Здравствуйте, Дарней, Вы писали:
AVC>>Другой миф (IMHO) — о каких-то небывалых преимуществах функционального программирования перед императивным. Д>нет здесь такого мифа
Тем лучше.
Просто у меня сложилось такое впечатление.
Уточни, что ты имеешь в виду:
1) что на RSDN никто не утверждает, что функциональные языки лучше императивных;
2) что принципиальные (не 'маргинальные' ) преимущества функциональных языков не являются мифом?
Интересно, тебе не понравилось только высказвание Вирта о функциональных языках?
Или ты также уверен, что архитектура Неймана плоха?
AVC>>Но Вирт указал причину, по которой он считает это преимущество маргинальным. На его взгляд активные объекты (владеющие собственым потоком) еще лучше, нет надобности переходить на функциональные языки. Д>Каким образом эти самые активные объекты могут помочь распараллеливать задачу? Давай рассмотрим это на примере задачи умножения матриц.
Активный объект — это поток + собственные локальные переменные объекта.
В определенном смысле, это развитие идеи монитора.
А что уж такого страшного в задаче умножения матриц?
Пусть у нас есть на входе матрицу A (размерностью mxt) и матрицу B (размерностью txn).
На выходе надо получить матрицу C размерностью mxn.
Т.к. элементы матрицы C не зависят друг от друга, то в принципе вычисление матрицы можно разбить на mxn потоков.
Добавляю в библиотеку процедуру умножения матриц с использованием многопоточности. И пользуюсь ей.
Ты хочешь сказать, что в случае функционального языка компилятору проще распараллелить код.
Но, в принципе, отсутствие побочных эффектов у функции компилятор может установить и для императивного языка, со всеми вытекающими последствиями.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, AVC, Вы писали:
AVC>1) что на RSDN никто не утверждает, что функциональные языки лучше императивных;
Таки утверждают. Ты только забыл добавить — "для некоторых задач"
AVC>2) что принципиальные (не 'маргинальные' ) преимущества функциональных языков не являются мифом?
именно так — не являются. Их подтверждают вполне конкретными делами и проектами. В отличие от.
AVC>Интересно, тебе не понравилось только высказвание Вирта о функциональных языках? AVC>Или ты также уверен, что архитектура Неймана плоха?
Текущая архитектура мне тоже не очень нравится. Но как программиста меня это практически не беспокоит
AVC>А что уж такого страшного в задаче умножения матриц? AVC>Пусть у нас есть на входе матрицу A (размерностью mxt) и матрицу B (размерностью txn). AVC>На выходе надо получить матрицу C размерностью mxn. AVC>Т.к. элементы матрицы C не зависят друг от друга, то в принципе вычисление матрицы можно разбить на mxn потоков. AVC>Добавляю в библиотеку процедуру умножения матриц с использованием многопоточности. И пользуюсь ей.
А теперь — внимание — вопрос на миллион. Каким образом активные объекты должны упростить эту задачу, по сравнению с существующими языками, например — C#?
AVC>Но, в принципе, отсутствие побочных эффектов у функции компилятор может установить и для императивного языка, со всеми вытекающими последствиями.
Теоретически — да. Только для того, чтобы извлечь из этого реальную пользу, придется писать довольно специфический код — без изменяемых переменных, с активным применением рекурсий и т.д.
Тебе это ничего не напоминает?
Это был пункт раз. А пункт два — где ты видел такие компиляторы?
Здравствуйте, Дарней, Вы писали:
AVC>>А что уж такого страшного в задаче умножения матриц? AVC>>Пусть у нас есть на входе матрицу A (размерностью mxt) и матрицу B (размерностью txn). AVC>>На выходе надо получить матрицу C размерностью mxn. AVC>>Т.к. элементы матрицы C не зависят друг от друга, то в принципе вычисление матрицы можно разбить на mxn потоков. AVC>>Добавляю в библиотеку процедуру умножения матриц с использованием многопоточности. И пользуюсь ей. Д>А теперь — внимание — вопрос на миллион. Каким образом активные объекты должны упростить эту задачу, по сравнению с существующими языками, например — C#?
Здесь, как мне кажется, и активные объекты как таковые не нужны.
Достаточно принципа локальности.
Если я напишу что-то вроде
matrix operator*(const matrix &a, const matrix &b) /* здесь можно добавить какое-нибудь ключевое слово вроде nosideeffect */
{
matrix c;
int i, j, k;
for (i = 0; i < m; ++i)
for (j = 0; j < n; ++j) {
c[i][j] = 0;
for (k = 0; k < t; ++k)
c[i][j] += a[i][k] * b[k][j];
}
return c;
}
то, IMHO, распараллеливание может быть добавлено компилятором как вполне рядовая оптимизация.
И не надо забивать голову специфическими проблемами ФЯ.
AVC>>Но, в принципе, отсутствие побочных эффектов у функции компилятор может установить и для императивного языка, со всеми вытекающими последствиями.
Д>Теоретически — да. Только для того, чтобы извлечь из этого реальную пользу, придется писать довольно специфический код — без изменяемых переменных, с активным применением рекурсий и т.д. Д>Тебе это ничего не напоминает?
Необязательно избегать использования переменных.
Достаточно, если это будут локальные переменные.
Если функция меняет только свои локальные (имеющие одно с ней время жизни и недоступные из других функций) переменные, то она не приводит к побочным эффектам. А разве не это главное?
IMHO, здесь важна локальность переменных, а не их полное отсутствие.
Д>Это был пункт раз. А пункт два — где ты видел такие компиляторы?
Просто это было не так актуально, IMHO.
Точно так же и функциональные языки (до последнего времени?) обещали эффективность и распараллеливание только в потенции.
Но существует одно качество, которое нельзя купить, — это надежность. Цена надежности — погоня за крайней простотой. Это цена, которую очень богатому труднее всего заплатить.
Здравствуйте, Курилка, Вы писали:
К>Набрёл на довольно интересный пост, спорный конечно, но основная мысль даже не вынесенная в заголовок, а в том, что архитектура фон Неймана — не единственная возможная схема, но на неё завязаны большинство современных языков программирования. К>Но возникает вопрос — а что можно противопоставить им? Какие языки будут хорошо ложиться на архитектуру Cell? К>(в статье приводится Erlang, насколько он подходит не берусь утверджать, а с другой стороны 1 язык это маловато)
Ну он, вообще-то, не столько о компьютерах, сколько о том, что "you'll just have to find an approach that works for you personally" (найдите, мол, подход к обучению, который будет работать персонально для вас). Да и вообще — have a fun! Фон Нейманом он иллюстрирует влияние привычки на положение дел.
Притом рассуждает иной раз так, что мама, не горюй. Как архитектура Cell принципиально противоречит фон Нейману? Или в более общем смысле — машине Тьюринга? Там что, процессор процессором не является? Или память — это не память? AFAIK, основное отличие от x86 — в явном прицеле на параллельные вычисления и развитые коммуникации. Но всё равно это никак не отрицает того, что набор инструкций а) имеет место быть и это ключевое понятие, и б) набор инструкций будет тем быстрее пройден процессором, чем меньше потребуется операций с внешними по отношению к процессору устройствами (общей памятью, синхронизациями, коммуникациями и т.п.). Вуаля, для достижения наивысшей производительности снова вспоминаем об архитектурных особенностях, т.е., читай, о фон Неймане.
Так что, вопрос о языках для Cell, это вопрос о языках с поддержкой параллелизма, а никакой не contra-von Neuman. Кстати, "в лоб" параллелизм можно и на обычном C поддержать. Набор инструкций, это что? Правильно, это — процедура.
PS.: Вот, всё-таки, русскую интеллигенцию погубит привычка читать между строк, даже если ничего там не написано.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
AVC>matrix operator*(const matrix &a, const matrix &b)
AVC>/* здесь можно добавить какое-нибудь ключевое слово вроде nosideeffect */
AVC>{
AVC> matrix c;
AVC> int i, j, k;
AVC> for (i = 0; i < m; ++i)
AVC> for (j = 0; j < n; ++j) {
AVC> c[ i ][j] = 0;
AVC> for (k = 0; k < t; ++k)
AVC> c[ i ][j] += a[ i ][k] * b[k][j];
AVC> }
AVC> return c;
AVC>}
AVC>
AVC>то, IMHO, распараллеливание может быть добавлено компилятором как вполне рядовая оптимизация. AVC>И не надо забивать голову специфическими проблемами ФЯ.
Ну да, создание копии. И никаких проблем.
Проблемы с concurrency так или иначе решаются, но дело в том, что при некоторых консервативных предположениях, можно _существественно_ разгрузить накладные расходы на обеспечение параллелизма.
Пример такого предположения — отсутствие побочных эффектов. Позволяет, например, выкинуть локи, мьютексы и прочие семафоры, и облегчить threading model. Пример языков с лёгковесными потоками (процессами): Erlang, GHC Haskell, GForth.
На этой диаграммке всё видно, в частности отрыв "лёгкой" многопоточности от "тяжёлой".
(В этом тесте запускается 500 потоков, что для Эрланга — просто детский лепет — для него и 50000 по зубам, если интересно могу привести рекорд).
AVC>Но, в принципе, отсутствие побочных эффектов у функции компилятор может установить и для императивного языка, со всеми вытекающими последствиями.
Да, конечно. Только таких функций будет очень и очень мало. Как только метод какого-нибудь класса обращается к своему полю с целью модификации — появляется побочный эффект, что существенно усложняет анализ. Кроме того, потенциальное существование таких функций не позволяет сделать параллельность легковесной.
Ограничиться в императивных языках только модификацией локальных переменных попросту означает эмулировать функциональный стиль на таком языке. При отсутствии подходящей нотации, такая "эмуляция" обойдётся дорого как для программиста, так для процессора.
Функциональные языки называются таковыми не потому, что запрещают побочные эффекты (это вообще неверно для Erlang и Ocaml), а потому, что они позволяют скрыть сложность при реализации функций без побочных эффектов за счёт удобной нотации. (хотя в ФЯ ещё много чего есть кроме этого )
AVC>Просто это было не так актуально, IMHO. AVC>Точно так же и функциональные языки (до последнего времени?) обещали эффективность и распараллеливание только в потенции.
Насколько велика область задач, где нужен массивный параллелизм? Скорее мала, чем велика. Это одна из "стратосфер человеческой мысли", и туда с обычными молотками и гвоздями не суются. Там нужны более тонкие инструменты
LCR>Пример такого предположения — отсутствие побочных эффектов. Позволяет, например, выкинуть локи, мьютексы и прочие семафоры, и облегчить threading model. Пример языков с лёгковесными потоками (процессами): Erlang, GHC Haskell, GForth.
Как я понял под легкими потоками имеются в виду потоки не преключающие контекст (фиберы в Win32), так это хак, аппаратно не распаралеливается, к тому же легко реализуется и на C++ и на C# и на питоне(10000 потоков тоже не проблема на интерпретаторе).
LCR>render_spawn(1) ->
LCR> ok.
LCR>render_spawn(N) when is_integer(N) ->
LCR> spawn(render_module, render, []),
LCR> render_spawn(N - 1).
LCR>% в модуле render_module
LCR>render() ->
LCR> % чего-то тут рендерим...
... а вот здесь самое интересное
LCR> ok.
LCR>
FR,
LCR>>Пример такого предположения — отсутствие побочных эффектов. Позволяет, например, выкинуть локи, мьютексы и прочие семафоры, и облегчить threading model. Пример языков с лёгковесными потоками (процессами): Erlang, GHC Haskell, GForth.
FR>Как я понял под легкими потоками имеются в виду потоки не преключающие контекст (фиберы в Win32), так это хак, аппаратно не распаралеливается, к тому же легко реализуется и на C++ и на C# и на питоне(10000 потоков тоже не проблема на интерпретаторе).
Не обязательно — это может быть что-то своё. В Erlang RTS процессы не зависят от существования/несуществования фиберов/потоков в конкретной ОС. Главное — обеспечение параллелизма без накладных расходов.
Разумеется, фиберами реализуется достигается облегчения накладных расходов. Но за счёт чего? За счёт обеспечения ручного распараллеливания. Да, да, теми самыми мозолистыми ручками. Нужно будет следить, чтобы какая-то операция не начала выполняться слишком долго, иначе вся параллельность накрывается медным тазом. А учитывая, что нам лёгкая параллельность нужна не для любви к искусству, а скажем, чтобы достичь предела в 100000 потоков управления на средненькой машинке, то твоё "легко" становится как бы гхм... не таким лёгким, что ли...
У такого ручного труда возникнут (обязательно возникнут!) проблемы с масштабированием.
Кроме того, фиберы есть не на многих осях. Тогда в чём прикол фиберов? В том, что иногда кое-где их полезно ввернуть вместо потоков, дабы тормоза снять. Гапертон как-то рассказывал о таком случае — в его случае это было что доктор прописал. Универсален ли этот подход? Думаю, что нет.