Is Haskell slow?
От: Аноним  
Дата: 25.12.10 14:35
Оценка: :))) :)
Говорят что хаскель медленоват.
Интересно, а разве нельзя использовать Glasgow Haskell Compiler, который сконвертирует хаскель в Сишный код?
Re: Is Haskell slow?
От: deniok Россия  
Дата: 25.12.10 14:46
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Говорят что хаскель медленоват.

А>Интересно, а разве нельзя использовать Glasgow Haskell Compiler, который сконвертирует хаскель в Сишный код?

Ну, собственно, все так и делают. Просто реализация ленивой модели вычислений ведёт к некоторым накладным расходам в рантайме. Если максимальное быстродействие критично, то лучше писать на чём-нибудь низкоуровневом, на том же C, например. Или аккуратно расставлять strictness флаги в своём коде.
Re: Is Haskell slow?
От: Rtveliashvili Denys Великобритания  
Дата: 25.12.10 15:20
Оценка:
А>Говорят что хаскель медленоват.
А>Интересно, а разве нельзя использовать Glasgow Haskell Compiler, который сконвертирует хаскель в Сишный код?

Две глупости сразу.

Во-первый, в общем случае он не медленноват.
Во-вторых, просто перевод его Сишный код мало что меняет. Это что, карго культ такой, что код на Це обязательно быстрый?

На данный момент в GHC, как мне видится, основные причины тормозов следующие:
1. слабосьть компилятора в таких областях, как strictness analysis, escape analysis
2. похоже GHC не может понять, когда можно использовать thread-local память. Также часто не просекает, когда можно держать данные в небольшом блоке и вместо этого лезет в heap.
3. неспособность FFI работать с структурами данных, передаваемыми по значению а не по ссылке
4. нет реализации некоторых полезных примитивов вроде bid endian <-> small endian и float/double -> binary representation
Re[2]: Is Haskell slow?
От: lovesan  
Дата: 28.12.10 23:17
Оценка:
Здравствуйте, Rtveliashvili Denys, Вы писали:

RD>3. неспособность FFI работать с структурами данных, передаваемыми по значению а не по ссылке


Это проблема не только хаскелевских FFI.
Вообще, если конкретнее, то проблема тут в Си.
Re[3]: Is Haskell slow?
От: Rtveliashvili Denys Великобритания  
Дата: 01.01.11 11:56
Оценка:
RD>>3. неспособность FFI работать с структурами данных, передаваемыми по значению а не по ссылке

L>Это проблема не только хаскелевских FFI.

L>Вообще, если конкретнее, то проблема тут в Си.

Почему проблема в С?
Re[2]: Is Haskell slow?
От: Rtveliashvili Denys Великобритания  
Дата: 07.01.11 19:00
Оценка:
А>>Интересно, а разве нельзя использовать Glasgow Haskell Compiler, который сконвертирует хаскель в Сишный код?

D>Ну, собственно, все так и делают. Просто реализация ленивой модели вычислений ведёт к некоторым накладным расходам в рантайме. Если максимальное быстродействие критично, то лучше писать на чём-нибудь низкоуровневом, на том же C, например. Или аккуратно расставлять strictness флаги в своём коде.


Насколько я разбираюсь в медицине

а) при компиляции haskell через C ленивость никуда не девается. Наоборот, могут быть проблемы из-за того что всякие хитрые трюки реализовать на C не столько тривиально.

б) ленивая модель вычислений ведет к часто непродуктивным расходам в рантайме. Особенно, когда эта ленивость и даром не нужна.

Пример:
sum $ map (+1) [1..n]


Нормальный компилятор мог бы догадаться, что результат — число. И при попытке получить это число вычислил бы результат "энергично". Но обычно сооружается куча глупого кода, в результате чего все делается "лениво" и через пень-колоду. Как правило, выделяя n*k объектов, постоянно проверяя вычислены ли thunkи и т.д.
Re[3]: Is Haskell slow?
От: deniok Россия  
Дата: 07.01.11 22:26
Оценка:
Здравствуйте, Rtveliashvili Denys, Вы писали:


RD>а) при компиляции haskell через C ленивость никуда не девается. Наоборот, могут быть проблемы из-за того что всякие хитрые трюки реализовать на C не столько тривиально.


Ничего не понял... Ленивость не девается, да. Зачем ей куда-то деваться?
Программы в любом случае транслируются из STG-языка в C--, а потом уже в машинный код. Но из-за полиморфных HOF (скажем в zipWith я могу передать функцию хоть двух, хоть трёх, хоть 20 аргументов) должна использоваться довольно специфическая модель исполнения. В GHC пробовали eval/applay и более традиционную push/enter — для Хаскеля первая оказалась лучше.

RD>б) ленивая модель вычислений ведет к часто непродуктивным расходам в рантайме. Особенно, когда эта ленивость и даром не нужна.


RD>Пример:
sum $ map (+1) [1..n]


RD>Нормальный компилятор мог бы догадаться, что результат — число. И при попытке получить это число вычислил бы результат "энергично". Но обычно сооружается куча глупого кода, в результате чего все делается "лениво" и через пень-колоду. Как правило, выделяя n*k объектов, постоянно проверяя вычислены ли thunkи и т.д.


Нормальный программист мог бы мог бы догадаться, что результат — число, вычисляемое за три арифметических операции
n * (n + 3) `div` 2
и не парил бы мозги компилятору
Re: Is Haskell slow?
От: Трурль  
Дата: 12.01.11 06:11
Оценка: :)
Здравствуйте, Аноним, Вы писали:

А>Говорят что хаскель медленоват.

А>Интересно, а разве нельзя использовать Glasgow Haskell Compiler, который сконвертирует хаскель в Сишный код?

Так ассемблер же быстрее си.
Re[4]: Is Haskell slow?
От: Rtveliashvili Denys Великобритания  
Дата: 15.01.11 20:17
Оценка:
RD>>а) при компиляции haskell через C ленивость никуда не девается. Наоборот, могут быть проблемы из-за того что всякие хитрые трюки реализовать на C не столько тривиально.

D>Ничего не понял... Ленивость не девается, да. Зачем ей куда-то деваться?


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

D>Программы в любом случае транслируются из STG-языка в C--, а потом уже в машинный код.


Да ну? Даже если кодогенерация идет через С или LLVM? Не верю. Там С-- и даром не нужен.

D>Но из-за полиморфных HOF (скажем в zipWith я могу передать функцию хоть двух, хоть трёх, хоть 20 аргументов) должна использоваться довольно специфическая модель исполнения. В GHC пробовали eval/applay и более традиционную push/enter — для Хаскеля первая оказалась лучше.


Спору нет, все так и есть. Однако справедливости ради следует заметить, что обычно типы известны довольно точно, и компилятор мог бы этим воспользоваться. Но как правило этого не делает.

RD>>б) ленивая модель вычислений ведет к часто непродуктивным расходам в рантайме. Особенно, когда эта ленивость и даром не нужна.


RD>>Пример:
sum $ map (+1) [1..n]


RD>>Нормальный компилятор мог бы догадаться, что результат — число. И при попытке получить это число вычислил бы результат "энергично". Но обычно сооружается куча глупого кода, в результате чего все делается "лениво" и через пень-колоду. Как правило, выделяя n*k объектов, постоянно проверяя вычислены ли thunkи и т.д.


D>Нормальный программист мог бы мог бы догадаться, что результат — число, вычисляемое за три арифметических операции
n * (n + 3) `div` 2
и не парил бы мозги компилятору


Похоже Вы предпочитаете прикалываться над искусственным (и специально простым) примером, а не обсудить проблемы существующего компилятора.
Re[5]: Is Haskell slow?
От: deniok Россия  
Дата: 15.01.11 21:57
Оценка:
Здравствуйте, Rtveliashvili Denys, Вы писали:

RD>>>Пример:
sum $ map (+1) [1..n]


RD>>>Нормальный компилятор мог бы догадаться, что результат — число. И при попытке получить это число вычислил бы результат "энергично". Но обычно сооружается куча глупого кода, в результате чего все делается "лениво" и через пень-колоду. Как правило, выделяя n*k объектов, постоянно проверяя вычислены ли thunkи и т.д.


D>>Нормальный программист мог бы мог бы догадаться, что результат — число, вычисляемое за три арифметических операции
n * (n + 3) `div` 2
и не парил бы мозги компилятору


RD>Похоже Вы предпочитаете прикалываться над искусственным (и специально простым) примером, а не обсудить проблемы существующего компилятора.


Хорошо. Что предлагается делать компилятору в программе
sum $ take 3 $ map (+1) [1..100500+n]

Результат — число. При попытке получить это число вычислять результат "энергично"? Разместить в памяти список на 100500+n элементов, увеличить каждый элемент на 1, а затем просуммировать первые его три элемента? Нет? А здесь
sum $ take n $ map (+1) [1..100500+n]

При маленьких n считать лениво, а при больших энергично?
Re[6]: Is Haskell slow?
От: Rtveliashvili Denys Великобритания  
Дата: 18.01.11 10:48
Оценка:
RD>>Похоже Вы предпочитаете прикалываться над искусственным (и специально простым) примером, а не обсудить проблемы существующего компилятора.

D>Хорошо. Что предлагается делать компилятору в программе

D>
sum $ take 3 $ map (+1) [1..100500+n]

D>Результат — число. При попытке получить это число вычислять результат "энергично"? Разместить в памяти список на 100500+n элементов, увеличить каждый элемент на 1, а затем просуммировать первые его три элемента? Нет? А здесь
D>
sum $ take n $ map (+1) [1..100500+n]

D>При маленьких n считать лениво, а при больших энергично?

1. В данном случае всегда считать энергично.

2. Умный комприлятор легко может догадаться, что список этот видно только в контексте этого выражения, так что хранить его в памяти и даром не надо. Поэтому и создавать этот список не нужно. Он вообще не должен быть в скомпилированном коде. Как вариант, выражение [1..100500+n] следует превратить в одну переменную и код, играющий роль итератора (a-la fusion). Причем без всяких этих богомерзких вручную написанных rewrite rules. Что-то вроде вот этого (псевдоассемблер):

; блок данных
upper_bound:
  data long
item:
  data long

; инициализация
init:
  ; предполагаем, что регистр acc хранит значение n
  add acc, 100500
  mov upper_bound, acc
  mov item, 0
  jpm #return_from_init

; итератор
next_val:
  mov acc, item
  inc acc
  cmp acc, upper_bound
  jg #end_of_list ; переход по адресу, соответствующему концу списка
  jpm #next_element_of_list ; переход по адресу, соответствующему считыванию очередного элемента списка. сам элемент - в регистре acc


Ну как, покатит? Или есть принципиальная проблема, почему так делать нельзя и приходится платить цену за ленивость вычислений да захламлять heap?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.