Re[6]: вдогонку
От: Pzz Россия https://github.com/alexpevzner
Дата: 30.10.08 13:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


При соблюдении двух услових:
Re[8]: Жизнь внутри метода
От: Andrei F.  
Дата: 30.10.08 13:03
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Из сообщений z00n, я понял, что тебе недостаточно, что функциональные структуры данных существуют и работают.


Меня интересует, насколько хорошо они работают для данной конкретной задачи. Если на каждый чих пользователя будут копироваться целые пачки объектов — это точно не хорошо.
А еще меня интересует, какие преимущества дает использование идеологии ФП для данной задачи.
Вроде я не слишком многого хочу, не так ли?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[12]: Жизнь внутри метода
От: WolfHound  
Дата: 30.10.08 13:15
Оценка: 5 (1)
Здравствуйте, AndrewVK, Вы писали:

AVK>Ты не мог бы вкратце рассказать суть? Читать 22 страницы текста как то лень.

Disclaimer: Статью читал давно некоторые детали мог немного переврать.
Вкраце так:
Ребятишки начали писать компилятор С-- на окамле.
И подумали: У нас же окамл, а не хаскель какойнибудь. Будем использовать изменяемые данные в оптимизаторе.
И начали они их использовать.
Даже в конце концов оно у них заработало.
Но гемороя по накату и главное откату изменений было столько что они потонули в багах.
Решили попробовать переписать используя паттерн zipper. Позволяющий дешево "модифицировать" неизменяемые структуры.
По началу боялись что zipper'ы сильно прогрузят ГЦ. Но тк баги совсем заели делать было нечего.
Но о чудо! Когда переписали компилятор начал работать быстрее.
Да и кода стало почти в 3 раза меньше и проще.
Так как производилась "модификация" откат стал тривиален (просто возвращаемся к версии до "модификации"). И "модификации" начали использовать более агрессивно.
Как следствие добавили кучу оптимизаций на которые раньше они не решались.
... << RSDN@Home 1.2.0 alpha rev. 745>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[13]: Жизнь внутри метода
От: Pavel Dvorkin Россия  
Дата: 30.10.08 13:29
Оценка: -1
Здравствуйте, Sinclair, Вы писали:

S>То есть тебе не очевидно, что твоя программа "с параллельностью", запущенная на одном ядре, будет менее эффективной, чем твоя же программа "без параллельности"?


Не только не очевидно, но в общем случае и неверно. И, возможно, даже в этом конкретном случае. Да, именно на одном ядре, будет более эффективна параллельная . Я же тебе уже объяснял — если потоки большую часть времени проводят в ожидании, распараллеливание на одном ядре может дать вплоть до N-кратного улучшения — просто потому, что когда один поток ждет, другой работает, а при одном потоке придется ждать.

Вот смотри — 10 временных единиц я суммирую, а потом читаю с диска, на это уходит 90 временных единиц. Пока не прочитается, суммировать не могу. И цикл по всему этому. Итого я загружаю процессор на 10%. А теперь 2 потока. 10 временных единиц каждый поток суммирует, 90 единиц ждет. Теперь оба потока вместе могут загрузить процессор на 20%. И т.д. Конечно, при 10 потоках 100% не получится, вмешаются другие факторы, которыми я тут пренебрег, но тенденция именно такая.

В данной же программе сидит GetPixel в цикле. GetPixel — это вызов ядра Windows (точнее, win32k.sys), int 2eh. Что там в ядре в этой ситуации делается — точно я , конечно, не знаю, но вот что могу сказать точно — при запуске моей программы в той части, где идет параллельная обработка, загрузка процессорв по Taskman составила всего лишь 53%. Поскольку мой код готов загрузить его на 100% (там только суммирование), то, очевидно, ожидание на GetPixel занимает почти половину времени. Что там за ожидание и чего — это не ко мне вопрос, я могу лишь предполагать. А пока что мой код хоть и готов загрузить оба ядра на 100%, да GetPixel не дает. Поэтому не исключаю, что даже на одном процессоре он будет быстрее, чем нераспараллеленный код. А может, нет, так как hdc я обоим потокам подсунул один и тот же (а мог бы и разный дать), и если на нем стоит мютекс, то ничего не выйдет. Такие вопросы надо конкретно решать, с учетом специфики задачи. Почитай форум по Win32, там это обсуждалось ИМХО, да и здесь тоже.

И вообще распараллеливание — это совсем не очевидное действие, где можно сказать — AsParallel и ждать, когда галушки в рот посыпятся. Много здесь факторов, которые могут сделать теоретически совершенно правильное решение никуда не годным. И наоборот тоже.

>В каких бы терминах мы ни мерили — в секундах, в тактах, в байтах или еще в чем?


Нет уж, давай определись. Секунды (время) — ты вчера сказал, что тебя не устраивает. Такты — это те же секунды с учетом числа ядер. Байты — это совсем другая опера, надеюсь, тебе не надо напоминать, что память и время — конкуренты, это на 1 курсе рассказывают. У компилятора С++, кстати, есть оптимизация по времени и оптимизация по размеру. Так что сначала определи точно, потом и обсудим.

S>Ты уже определись — то ли ты крутой специалист по оптимизации программ, то ли необученный новичок.


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

S>Если первое — то непонятно, зачем тебе разжевывать, куда деваются такты и байты памяти при лишних вызовах WaitForMultipleObjects и new[].


О господи! Это уж за всякие пределы выходит. Придется ликбез провести.

WaitForMultipleObjects практически никаких тактов вообще не требует в user mode. Все, что делается при ее вызове — засылка параметров в стек и int 2eh. Все. Поток больше делать ничего не может, так как спит сном праведника и сам себя разбудить не может. Просто в ядре Windows он теперь добавлен в список тех потоков, которые на этом ивенте/мютексе... ждут. Он спит. И когда мютекс сей освободится — ядро проверит его (потока) приоритет, и если он выше приоритета текущего потока, даст ему управление, а если нет — в очередь готовых потоков. Так что WaitFor... работает почти целиком в kernel-mode. А в этом kernel mode этот поток — лишь один из многих, котррыми система управляет. Это все называется накладные расходы, если их не хочешь — возвращайся в DOS. И вопрос в том, перекрывает ли ожидаемый выигрыш от распараллеливания эти расходы или нет.

А new — это тоже накладные расходы, хоть и (чаше всего) не в ядре. В идеале наилучшее по времени распределение памяти было в Фортране -4, так как там вообще динамического распределения памяти не было. Но это шутка, а реально мы ее вынуждены выделять. Опять-таки — как эти накладные расходы соотносятся с ожидаемым эффектом ? Тут и так все ясно — количество chunk равно числу процессоров, а количество new — числу chunk, то есть 2-4-8..., но не тысячи. И на фоне тех 1-2 сек, что требуется для циклов с GetPixel — это все равно, что монетку положить на автомобильные весы
With best regards
Pavel Dvorkin
Re[15]: Жизнь внутри метода
От: Mirrorer  
Дата: 30.10.08 13:32
Оценка: +2
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ты не понял. На шарпе это 1:1 можно сделать, никто и не спорит. Я просил это на LinQ реализовать.


По первым двум пунктам реализовать это на PLInq не составит труда. Мы любую коллекцию данные IEnumerable можем обрабатывать как AsParallel. а как энумератор будет бегать по элементам — хошь задом наперед хошь по диагонали это вопрос третий.

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

Другой вопрос в том, что принципиальная возможность имеется.
допустим так AsParallel(for_even_processes_set_priority_low)

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

а по поводу ассемблера. Таки да. Любой код рано или поздно будет переведен в ассемблер. Но есть нюанс. Человек не сможет написать такой же эффективный ассемблер как компилятор просто физически. Делать на асме кроссмодульные оптимизации хотя бы дестятка двух модулей это чревато вывихом мозга как минимум.

Поэтому чисто теоретически — да, эффективнее ассемблера ничего нет. Но в практическом плане использование высокоуровневых абстракций позволяет генерировать более эффективный код исключитлеьно за счет того, что компилятору намного проще анализировать весь граф вызовов n модулей и сделать JIT код конкретный процессор с оптимизациями, чем человеку.

конечно JIT не панацея. И высокоуровневые вещи вроде Plinq не настолько универсальны как ручное управление потоками. Но они дают возможность избавиться от туевой хучи головной боли и тупых задач вроде оптимизации кода на асме под новый процессор с немного другим размером кеша. Есть такое подозрение, что в 80 случаях из 100, а то и больше JIT+Plinq позволяют решить задачу проще и одновреенно эффективнее. А в остальных 20 случаях может быть и наоборот.
Re[15]: Жизнь внутри метода
От: Mirrorer  
Дата: 30.10.08 13:34
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Сравнивать же твои результаы с моими бессмысленно — сначала надо о размере окна договориться

Не могу не согласиться
Re[13]: Жизнь внутри метода
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.10.08 13:39
Оценка:
Здравствуйте, WolfHound, Вы писали:

AVK>>Ты не мог бы вкратце рассказать суть? Читать 22 страницы текста как то лень.

WH>Disclaimer: Статью читал давно некоторые детали мог немного переврать.
WH>Вкраце так:
WH>Ребятишки начали писать компилятор С-- на окамле.
WH>И подумали: У нас же окамл, а не хаскель какойнибудь. Будем использовать изменяемые данные в оптимизаторе.
WH>И начали они их использовать.
WH>Даже в конце концов оно у них заработало.
WH>Но гемороя по накату и главное откату изменений было столько что они потонули в багах.

Но это же частный случай? Как из него следует, что всегда дешевле делать чисто функциональные структуры? С откатом все понятно. А если откат не нужен? За что мы будем платить повышенным расходом памяти и значительно более сложной реализацией самих структур (не говоря уж о том, что мутабельные структуры в фреймворке уже есть)?
Кроме того, есть всякие штуки вроде System.IO.Stream. Его нефункциональность прошита в базовые слои ОС. Можно его красиво обернуть, по крайней мере избавив от состояния, но с откатами один черт без большого оверхеда ничего не выйдет.
Вобщем, мораль всего этого простая — всегда надо включать голову, а не тупо следовать принципам и правилам. О чем, кстати, IT в заголовке топика явно упоминал.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[9]: Жизнь внутри метода
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.10.08 13:39
Оценка:
Здравствуйте, Andrei F., Вы писали:

AF>Меня интересует, насколько хорошо они работают для данной конкретной задачи. Если на каждый чих пользователя будут копироваться целые пачки объектов — это точно не хорошо.


Зачем целые пачки? Копируются обычно только изменения. Вон, тот же string в дотнете, вполне себе сооответствует принципам ФП, что не мешает эффективно работать с громадным количеством его экземпляров.

AF>А еще меня интересует, какие преимущества дает использование идеологии ФП для данной задачи.


Именно для этой — точно такое же, как и для любой другой: надежный и хорошо читаемый код, отсутствие побочных эффектов, дешевизна распараллеливания на микроуровне и реализации in memory transaction.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[10]: Жизнь внутри метода
От: Andrei F.  
Дата: 30.10.08 13:48
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Зачем целые пачки? Копируются обычно только изменения. Вон, тот же string в дотнете....


Ты явно даже не пытался понять суть того, о чем я говорил. Дальше можно не продолжать.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[14]: Жизнь внутри метода
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 30.10.08 14:02
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Вот смотри — 10 временных единиц я суммирую, а потом читаю с диска, на это уходит 90 временных единиц. Пока не прочитается, суммировать не могу. И цикл по всему этому. Итого я загружаю процессор на 10%. А теперь 2 потока. 10 временных единиц каждый поток суммирует, 90 единиц ждет. Теперь оба потока вместе могут загрузить процессор на 20%. И т.д. Конечно, при 10 потоках 100% не получится, вмешаются другие факторы, которыми я тут пренебрег, но тенденция именно такая.


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

Достаточно вместо GetPixel взять массив точек в памяти (выдрать с помощью GetDIBits). Потом можно сравнить результаты.
Re[11]: Жизнь внутри метода
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.10.08 14:07
Оценка:
Здравствуйте, Andrei F., Вы писали:

AF>Ты явно даже не пытался понять суть того, о чем я говорил. Дальше можно не продолжать.


Рылом не вышел?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[12]: Жизнь внутри метода
От: Andrei F.  
Дата: 30.10.08 14:15
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Именно для этой — точно такое же, как и для любой другой: надежный и хорошо читаемый код, отсутствие побочных эффектов, дешевизна распараллеливания на микроуровне и реализации in memory transaction.


Избавленный от побочных эффектов GUI — это феноменально. Изобретатель обезжиренного сала удавился от зависти. Все корифеи ФП рыдают от тоски, что не додумались до такой простой и гениальной идеи.

AVK>Рылом не вышел?


Нет, не рылом. Но хотя бы немного думать, прежде чем писать — это очень желательно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[13]: Жизнь внутри метода
От: IT Россия linq2db.com
Дата: 30.10.08 14:32
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

IT>>Картина Репина "Закат солнца в ручную". Ну-ну. Ты проценты распараллелить не в состоянии, какой нафиг JIT?


PD>Ты же вроде обещал прекратить дискуссию, так ?


Я и не дискутирую. Я констатирую факт.
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: Жизнь внутри метода
От: prVovik Россия  
Дата: 30.10.08 14:32
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Но о чудо! Когда переписали компилятор начал работать быстрее.

WH>Да и кода стало почти в 3 раза меньше и проще.

Как показывает практика, при переписываниях обычно именно так и происходит, причём независимо от используемых технологий
лэт ми спик фром май харт
Re[13]: Жизнь внутри метода
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 30.10.08 15:54
Оценка: +3
Здравствуйте, Andrei F., Вы писали:

AF>Избавленный от побочных эффектов GUI — это феноменально. Изобретатель обезжиренного сала удавился от зависти. Все корифеи ФП рыдают от тоски, что не додумались до такой простой и гениальной идеи.


GUI даже в чистых ФП языках есть уже ндцать лет. По делу есть что сказать?

AVK>>Рылом не вышел?


AF>Нет, не рылом. Но хотя бы немного думать, прежде чем писать — это очень желательно.


Аналогично. Если ты чего то не понял, это не означает, что оппонент дурак.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[6]: Жизнь внутри метода
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 30.10.08 23:58
Оценка: 6 (1) +3
Павел Лазаревич,

PD>Лет так 30 назад была такая система программирования Альфа, сделана была в Новосибирске Ершовым, поттосиным и др. На базе языка Алгол, но с расширениями. Так вот, там сложение матриц делалось еще проще

PD>real array a[1:n][1:m],b[1:n][1:m], c[1:n][1:m];
PD>// инициализация
PD>c := a + b;
PD>Проще некуда.

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


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

На данный момент необходимо иметь такой базовый набор выразительных средств (нотацию, язык — назовите как угодно), которая
1. Позволяет реализовать любой алгоритм в принципе
2. Позволяет реализовать любой алгоритм практически, причём реализация была или как можно более эффективной (учитывала конкретное окружение включая кэши, конвейеры, наличие нескольких ядер), или давала гарантии по эффективности или затратам памяти.

Несложный анализ показывает, что вышеназванная Альфа никак укладывается в требования выше. Чтобы попытаться накрыть ладонью всё множество алгоритмов, выделения кусочка кода и возможность обозвать его "+" явно недостаточно. Нужна модульность, много модульности, больше чем сейчас. Поясню на примере.

Допустим, вы реализовали умножение матриц, причём учли и кэши, и многопроцессорность, и учли специфику Intel/AMD и ещё много чего. То есть, ваш алгоритм стал очень очень быстрым, так что на любой машине это оказалась самая эффективная реализация.

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

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

А Таня, вдобавок, хочет взять ваш алгорить, и сделать так, чтобы вместо вещественных чисел были функции, да ещё и на комплексном пространстве.

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

Единственный разумный путь сделать счастливыми всех четырёх человек, как мне видится, это декларативно описать алгоритм и возложить знание об архитектуре и окружение на компилятор (так что компилятор и будет модулем optimize, можно считать что каждая функция описана как f = optimize f_). Такое декларативное описание присутствует в коде на Хаскеле, и в подавляющем большинстве случаев отсутствует в коде на C++, так что бедные Вася, Таня, Алиса и ваш покорный ученик должны заново изобретать свои многоугольные колёса.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[6]: вдогонку
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.10.08 04:39
Оценка: +3
S>Осталось понять, можно ли применить этот подход, оставаясь в рамках "наилучшим образом оптимизированной программы, написанной на ассемблере", и "можно ли сделать код эффективнее с помошью каких-то высокоуровневых конструкций". Об этом я напишу завтра, потому что сегодня пора домой
Итак, продолжаем разрывать шаблоны. Но перед тем, как перейти к основному обсуждению, сделаю два уточнения:
1. Напомню, что речь идет именно о сферических программах в вакууме. Мы не собираемся обсуждать возможности реально доступных компиляторов и сред исполнения. Во-первых, потому, что изначально вопрос формулировался именно в абстрактно-теоретических терминах, а во-вторых, потому, что иначе нам придется сравнивать реальные компиляторы с реальными программистами-ассемблерщиками, и тут совершенно неясно, слон кита заборет или всё-таки наоборот

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

Итак, вернемся к нашим "высокоуровневым конструкциям".
Пока что мы получили интуитивное представление о том, что неплохо бы выбирать решение в зависимости от свойств поступающих задач. Ассемблер достаточно гибок для того, чтобы помочь нам в простых случаях. Под простыми случаями я имею в виду такие, когда количество вариантов решения невелико. Ну вот сколько у нас алгоритмов сортировки для массива? В таком случае, расходы памяти на одновременное хранение всех этих программ не выходят за пределы разумного, а выбор сводится к традиционному conditional statement.

К сожалению, у этого подхода имеются свои ограничения.
Если "размеры" семейства программ-решений выходят за разумные пределы, то их суммарный объем становится препятствием для статической реализации. Это не такая уж редкая ситуация: как правило, некоторая задача делится на более мелкие подзадачи. Если у подзадач A1 и A2 — по четыре решения, то у задачи A, которая является суперпозицией этих двух задач, получается 16 решений.
В более сложных случаях мы можем наблюдать экспоненциальный взрыв пространства возможных решений. Реальный пример желающие могут пронаблюдать здесь.

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

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

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

Итак, изначальный вопрос пользовался "высокоуровневыми конструкциями", а не "runtime code generation".
Поясняю логическую взаимосвязь: вот у нас есть та часть программы, которая не меняется в процессе ее работы. И вот есть другая часть программы, которая таки меняется в процессе работы. На чем написана эта вторая часть? Я имею в виду — до того, как мы начали программу выполнять?

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

Вот, собственно, и всё. Sapienti Sat.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Жизнь внутри метода
От: Andrei F.  
Дата: 31.10.08 04:53
Оценка: -1
Здравствуйте, AndrewVK, Вы писали:

AVK>GUI даже в чистых ФП языках есть уже ндцать лет. По делу есть что сказать?


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

AVK>Аналогично. Если ты чего то не понял, это не означает, что оппонент дурак.


А когда этот оппонент доказывает мне одно, а в соседней ветке проталкивает прямо противоположное — вот тогда сомнения уже закрадываются...
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[14]: Жизнь внутри метода
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.10.08 04:57
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:
S>>То есть тебе не очевидно, что твоя программа "с параллельностью", запущенная на одном ядре, будет менее эффективной, чем твоя же программа "без параллельности"?
PD>Не только не очевидно, но в общем случае и неверно.
Павел, хватит придуриваться. Я говорю не про какой-то общий случай, а конкретно про твою конкретную программу.

PD>И, возможно, даже в этом конкретном случае. Да, именно на одном ядре, будет более эффективна параллельная . Я же тебе уже объяснял — если потоки большую часть времени проводят в ожидании, распараллеливание на одном ядре может дать вплоть до N-кратного улучшения — просто потому, что когда один поток ждет, другой работает, а при одном потоке придется ждать.

Павел, ты же такой крутой специалист. Что тебе непонятно? Что программа №1 делает всё в одном потоке — в том, в котором вызвали?
Или что программа номер 2 при вызове на 1 ядре занимается ерундой — выделяет память, создает объекты синхронизации, передает управление во второй поток и тупо садится ждать его выполнения?

S>>Ты уже определись — то ли ты крутой специалист по оптимизации программ, то ли необученный новичок.


PD>Лучше ты ознакомься сначала с основами параллельных вычислений и состояниями потоков, их переходами и т.д.

Павел, я с ними знаком.


S>>Если первое — то непонятно, зачем тебе разжевывать, куда деваются такты и байты памяти при лишних вызовах WaitForMultipleObjects и new[].


PD>О господи! Это уж за всякие пределы выходит. Придется ликбез провести.


PD>WaitForMultipleObjects практически никаких тактов вообще не требует в user mode. Все, что делается при ее вызове — засылка параметров в стек и int 2eh. Все. Поток больше делать ничего не может, так как спит сном праведника и сам себя разбудить не может. Просто в ядре Windows он теперь добавлен в список тех потоков, которые на этом ивенте/мютексе... ждут. Он спит. И когда мютекс сей освободится — ядро проверит его (потока) приоритет, и если он выше приоритета текущего потока, даст ему управление, а если нет — в очередь готовых потоков. Так что WaitFor... работает почти целиком в kernel-mode. А в этом kernel mode этот поток — лишь один из многих, котррыми система управляет. Это все называется накладные расходы, если их не хочешь — возвращайся в DOS. И вопрос в том, перекрывает ли ожидаемый выигрыш от распараллеливания эти расходы или нет.

Я фигею.

PD>А new — это тоже накладные расходы, хоть и (чаше всего) не в ядре. В идеале наилучшее по времени распределение памяти было в Фортране -4, так как там вообще динамического распределения памяти не было. Но это шутка, а реально мы ее вынуждены выделять. Опять-таки — как эти накладные расходы соотносятся с ожидаемым эффектом ? Тут и так все ясно — количество chunk равно числу процессоров, а количество new — числу chunk, то есть 2-4-8..., но не тысячи. И на фоне тех 1-2 сек, что требуется для циклов с GetPixel — это все равно, что монетку положить на автомобильные весы

Павел, еще раз напомню, что ты имел смелость сделать абстрактно-теоретическое заявление. Я тебе показываю, что твоя мегапараллельная программа при запуске на 1 ядре будет делать 1 new, не 2-4-8, и будет делать WaitForMultipleObjects, который нифига не бесплатный (ты замерь, сколько времени занимает WaitForMultipleObjects в случае свободного объекта). Я уж не говорю про то, что твой лишний поток сожрал 1 мегабайт адресного пространства ни за хрен собачий, что могло кого-то вытеснить в своп. И всё это можно было не делать. Потому что ядро всё равно одно, и ты всё равно не получишь выигрыша на вычислительной задаче.

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

По поводу мультипрограммирования тебе тут уже отвечали: речь не о распараллеливании ожидания. Хотя, конечно, опытным оптимизаторам известно, что даже для него применять потоки ядра — роскошь, а не средство передвижения. Если бы ты дал себе труд ознакомиться с архитектурой высокопроизводительных приложений, то убедился бы, что никто не выделяет "1 поток — 1 задача". Для распараллеливания ожидания эффективнее кооперативная многозадачность и программный параллелизм.
Причем опять же, пространство решений для неё слишком велико, чтобы покрыть его "оптимизированным кодом, написанным на ассемблере". Читать про свитч AXD-301. Там как раз задачи вроде тех, которые ты (как ты думаешь) любишь решать — ограниченная железка, чудовищная нагрузка. Наверное, там не должно быть места "высокоуровневым конструкциям" и "виртуальным машинам". Так? Увы. Всё как раз наоборот. Добро пожаловать в реальный мир.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Жизнь внутри метода
От: Pavel Dvorkin Россия  
Дата: 31.10.08 06:54
Оценка:
Здравствуйте, deniok, Вы писали:

D>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>И никак нельзя распараллелить иначе, чем Win32 (или на худой конец native API) позволит. С этим-то хоть ты согласен ? Вот ответь прямо — да или нет ?


D>Green threads


Это просто означает, что реального распараллеливания (то есть с квантованием времени и переключением в произвольный момент) там нет. Есть некое пседораспараллеливание, когда поток/процесс выполняет то одну часть кода, то другую. В любом случае OS может не дать этому потоку квант времени, и он будет спать и ждать, когда ему его дадут. И уж тем более здесь не удастся использовать те преимущества настоящей многопоточночти, как только речь пойдет об ожидании на объектах ядра. Стоит только начать ожидание — как блокируется поток Windows и все, ждите.
Кстати, для этого не надо никакой вирт. машины — посмотри фиберы.

И кстати, по твоей ссылке первая фраза

On a multi-core processor, native thread implementations can assign work to multiple processors, whereas green thread implementations cannot.
With best regards
Pavel Dvorkin
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.