Комментарии 21
1. Уже 7.6.2
2. Вот это меня в Haskell и удручает, что для должной производительности приходится испещрять код всякими {-# INLINE f #-}, {-# UNPACK #-} и явными определениями переменных, которые нужно посчитать только один раз. Что средства, с которых начинается обучение и которые более всего свойственны языку (списки, Maybe, Either) медленны.
2. Вот это меня в Haskell и удручает, что для должной производительности приходится испещрять код всякими {-# INLINE f #-}, {-# UNPACK #-} и явными определениями переменных, которые нужно посчитать только один раз. Что средства, с которых начинается обучение и которые более всего свойственны языку (списки, Maybe, Either) медленны.
+4
Да, отсутствие флага вроде
-finline-functions-by-default
— серьезное упущение. {-# NOINLINE #-}
же есть.0
П.2 явное преувеличение, dataflow-Фреймворки пишут не так и часто. Ну и Haskell не за производительность кода выбирают. Не встречался с обычными задачами, где тормоза были бы именно в Maybe/Either, а представить себе алгоритм, который упирался бы в обработку Maybe/Either сходу не могу.
0
Проблема в том, что клиентский код на этом фреймворке тоже приходится писать крайне внимательно, с прагмами и явными сигнатурами функций.
0
Это всё же достаточно специфичная задача, в таких задачах и на Си++ наивно не попишешь. То, что для такого языка можно получить быстрый код хотя бы так уже хорошо. Можно не бояться, что придётся переписывать всё из-за тормозов.
Нередко, кстати, встречается другое заблуждение, что на C++ можно получить быстрый код нахаляву, а меж тем наивный код на C++ и Haskell работают сравнимо, а именно такого кода больше всего.
Как раз скорость наивного кода более всего и интересна, т.е. насколько будет тормозить обычный код, и не придётся ли из-за этого всё переписывать.
Нередко, кстати, встречается другое заблуждение, что на C++ можно получить быстрый код нахаляву, а меж тем наивный код на C++ и Haskell работают сравнимо, а именно такого кода больше всего.
Как раз скорость наивного кода более всего и интересна, т.е. насколько будет тормозить обычный код, и не придётся ли из-за этого всё переписывать.
0
Это надо очень сильно постараться, чтобы написать на C++ так же медленно, как на «дефолтном» Хаскеле.
И на мой взгляд вопрос в Хаскеле не сколько в наивности, столько в бойлерплейте.
И на мой взгляд вопрос в Хаскеле не сколько в наивности, столько в бойлерплейте.
0
> Это надо очень сильно постараться, чтобы написать на C++ так же медленно, как на «дефолтном» Хаскеле.
Почему вы так считаете?
Я не делал специального сравнения, но не раз натыкался на различные типичные задачи, где наивные решения на C++ и Haskell были сравнимы с переменным лидерством.
Почему вы так считаете?
Я не делал специального сравнения, но не раз натыкался на различные типичные задачи, где наивные решения на C++ и Haskell были сравнимы с переменным лидерством.
+1
Сомневаюсь:
1) Откажитесь почти от всего STL.
2) Где в C++ обычное тело цикла, в Хаскеле вызов функции. Причем вызов в Хаскеле — это не просто аргументы на стек и
И так далее…
1) Откажитесь почти от всего STL.
std::string
, std::vector
и std::map
— это слишком быстро для Хаскеля. Только std::forward_list
, только хардкор.2) Где в C++ обычное тело цикла, в Хаскеле вызов функции. Причем вызов в Хаскеле — это не просто аргументы на стек и
call
, там же еще рантайм таскает по стеку туда-сюда кучу внутренних переменных.И так далее…
0
Я склонен не доверять предсказаниям, потому что тормозит, как известно, не там, где думает программист.
Так что это будет верно только если считать, что в Haskell тормозит всё и везде.
Про std::forward_list не понял, если честно. Или ByteString и Text это сродни forward_list, по-вашему?
Так что это будет верно только если считать, что в Haskell тормозит всё и везде.
Про std::forward_list не понял, если честно. Или ByteString и Text это сродни forward_list, по-вашему?
+1
В «дефолтном» Хаскеле для строк применяется
type String = [Char]
.0
А причём тут дефолтный Хаскель? Речь о «наивном» реально используемом коде, а там уже давным давно стандарт ByteString/Text.
0
Ах, если бы. Даже на hackage меньше половины пакетов зависят от bytestring либо text. (Всего пакетов, по данным Hayoo, 4750.)
0
> Это надо очень сильно постараться, чтобы написать на C++ так же медленно, как на «дефолтном» Хаскеле.
Попробуйте написать не числодробильню, а какой-нибудь компилятор или хотя бы работу с графами. Скорее всего придется сильно постараться в С++, чтобы догнать Хаскелл.
Попробуйте написать не числодробильню, а какой-нибудь компилятор или хотя бы работу с графами. Скорее всего придется сильно постараться в С++, чтобы догнать Хаскелл.
0
Не соглашусь, что стоит во всех структурах делать поля строгими. Зачастую это может ухудшить производительность, т.к. начнет вычисляться то, что могло бы и не вычисляться. UNPACK также может навредить, если его значение надо будет передавать в какую-либо ф-ю, ожидающую ленивое значение.
Вместо INLINE зачастую лучше INLINABLE, чтобы GHC сам решал инлайнить, или нет.
В целом, не стоит настолько хардкорно сразу все оптимизировать. Только на очень часто вызываемых кусках кода, причем каждый раз тестируя, действительно ли эта оптимизация дала какой-либо эффект.
Вместо INLINE зачастую лучше INLINABLE, чтобы GHC сам решал инлайнить, или нет.
В целом, не стоит настолько хардкорно сразу все оптимизировать. Только на очень часто вызываемых кусках кода, причем каждый раз тестируя, действительно ли эта оптимизация дала какой-либо эффект.
+1
Ваше замечание о полях верно в случае, если программа в целом написана в ленивом стиле, что с высокой производительностью само по себе не очень вяжется.
Насчет INLINABLE не согласен, GHC очень печется о лишней паре килобайт бинарника и сам почти ничего не инлайнит.
Насчет INLINABLE не согласен, GHC очень печется о лишней паре килобайт бинарника и сам почти ничего не инлайнит.
0
Тут все зависит от типа разрабатываемой программы. Для числодробильни важно инлайнить, разворачивать циклы, не делать лишних ветвлений и вообще ничего лишнего не делать. А для программ с более-менее развесистой логикой ленивость может запросто выиграть, т.к. не будет вычислять то, что не нужно.
GHC, возможно, не зря печется о лишних килобайтах, т.к. не всегда инлайн дает ускорение. Посмотрите на исходники того же Data.Map. Там именно INLINABLE и не везде.
GHC, возможно, не зря печется о лишних килобайтах, т.к. не всегда инлайн дает ускорение. Посмотрите на исходники того же Data.Map. Там именно INLINABLE и не везде.
0
Вообще у INLINABLE кажется немного другая семантика, с кросс-модульной компиляцией связанная. Так-то GHC и функции совсем без прагмы решает, встраивать или нет, теоретически.
0
Для строк есть
Text
, байтстринги (что и следует из названия) предназначены для хранения последовательностей байт, или вы за пределы ASCII не вылезаете и 0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Принципы быстрого Хаскеля под GHC