C vs Haskell: сравнение скорости на простом примере
Ранее мы сравнивали
одни программы на Си с другими программами на Си, которые отличаются от первых характерными для Хаскелла приёмами.
А теперь сравним программу на Си и программу на Хаскелле.
Выберем простейшую задачу прочитать содержимое файла и просуммировать 32-битных слов в нём.
Ниже — программа, решающая её на Хаскелле.
Насколько правильно, насколько эффективно — судить не берусь.
Но раз не побоялись выложить код на всеобщее обозрение, значит он приемлем для программистов на Хаскелле.
import System.Environment
import Data.Binary
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy.Internal as L
import System.IO
import qualified Data.ByteString.Lazy as L
import Data.Binary.Get
import Data.Word
main::IO()
main = do
args <- getArgs
a <- (calculateSumInFile (head args))
print a
calculateSumInFile:: FilePath->IO Word32
calculateSumInFile path =
withBinaryFile path ReadMode $ \h ->
let byWords s = do
w <- L.hGet h 4
if L.length w == 4 then
byWords $ s + runGet getWord32host w
else return s
in byWords 0
А теперь решение той же задачки на Си. Опущу неинтересное, чтобы не утомлять читателя лишними подробностями. Вот главное в коде:
. . .
fread(буфер, длина, 1, файл откуда);
. . .
_31 x = 0;
_31 i = 0;
_31* очередное слово = (_31*) буфер;
for (; i < длина; i += 4, ++очередное слово)
x += *очередное слово;
printf( "Результат: %d\n", x);
Забегая вперёд, скажу, что обе программки выдают одинаковый результат — ту сумму, которую надо вывести в консоль.
Это с большой вероятностью говорит, что оба примера правильно решают исходную задачу.
Для тестирования использовались те же компьютеры, что и в предыдущих тестах. А вот размер файла менялся от 1Мб до 256 Мб.
Опять замер проводился на компьютерах A, B и C, для каждого из них измерялось время прохождения теста на Си (первая колонка),
Хаскелл (вторая) и соотношение времени, затраченное программой на Хаскелл ко времени, затраченном программой на Си.
Вот полученные результаты:
|
A
|
B
|
C
|
Размер
|
C
|
Haskell
|
Соотн.
|
C
|
Haskell
|
Соотн.
|
C
|
Haskell
|
Соотн.
|
1 Мб
|
0,104
|
1,473
|
14,16
|
0,047
|
1,05
|
22,34
|
0,016
|
0,438
|
27,38
|
4 Мб
|
0,172
|
3,871
|
22,51
|
0,078
|
2,69
|
34,49
|
0,062
|
1,016
|
16,39
|
16 Мб
|
0,25
|
15,23
|
60,94
|
0,109
|
9,619
|
88,25
|
0,078
|
3,938
|
50,49
|
64 Мб
|
0,422
|
79,24
|
187,8
|
0,202
|
44,88
|
222,2
|
0,125
|
16,64
|
133,1
|
256 Мб
|
6,812
|
7645
|
1122
|
0,639
|
1070
|
1674
|
2,672
|
4017
|
1503
|
Вынесем соотношения в отдельную табличку:
|
A
|
B
|
C
|
1 Мб
|
14,16
|
22,34
|
27,38
|
4 Мб
|
22,51
|
34,49
|
16,39
|
16 Мб
|
60,94
|
88,25
|
50,49
|
64 Мб
|
187,8
|
222,2
|
133,1
|
256 Мб
|
1122
|
1674
|
1503
|
И построим график:
С увеличением размера файла соотношение времен исполнения на Хаскелл и Си взмывает по экспоненте.
Преобразуем результаты предыдущей таблицы, применив к ним функцию двоичного логарифма:
|
A
|
B
|
C
|
1 Мб
|
3,824
|
4,4816
|
3,895
|
4 Мб
|
4,492
|
5,108
|
4,034
|
16 Мб
|
5,929
|
6,4635
|
5,658
|
64 Мб
|
7,553
|
7,7957
|
7,057
|
256 Мб
|
10,13
|
10,709
|
10,55
|
В логарифмическом масштабе график более нагляден:
Выводы
Если размер файла небольшой (1 Мб), то разница между программками на Хаскелле и Си — в разы.
С возрастанием размера файла разница становится чудовищной, в несколько порядков.
Так что программирование на Хаскелл требует внимательности и аккуратности, не все его средства одинаково полезны.
Ещё одно любопытное наблюдение: компилятор Tiny CC для программки на Си подготовил исполняемый файл размером 3584 байтов.
А вот компилятор GHC «выдал на гора» 15Мб. Почувствуйте разницу. Оптимизировали, оптимизировали GHC, да так и не дооптимизировали.
Вывод Филипа Уодлера, одного из соавторов Хаскелла, о двухкратной разнице по скорости Си и Хаскелла,
легко опровергается простым примером. Это один из ответов на вопрос, почему Хаскелл так мало используется в отрасли.
Post Scriptum
Д.Ю.Караваев прислал мне программку, делающую то же самое, но на PL/1.
Запустил программку на компьютере конфигурации A, получил следующие результаты (время исполнения в процентах от программы на Си):
-
1 Мб — 98%
-
4 Мб — 91%
-
16 Мб — 94%
-
64 Мб — 85%
-
256 Мб — 86%
Объективности ради надо отметить, что время исполнения оказалось, как правило, меньше секунды.
Следовательно, погрешность измерений имела место быть.
Тем не менее, в целом отечественный компилятор PL/1 выглядит достойно на импортном фоне.
Post Post Scriptum
Нашёл задачку вычисления определителя квадратной матрицы на Хаскелле.
Автор — Борис Файфель, кандидат физико-математических наук, доцент Института прикладных информационных технологий и коммуникаций в Саратове.
Известен как разработчик HomeLisp.
Решил написать программку на Си, которая вычисляет то же самое,
чтобы увидеть разницу в скорости работы массивов на Си и списков на Хаскелле.
Чтобы была возможность сравнить, необходимо увеличить размерность матрицы. Для начала выбрал размер матрицы 512 на 512.
Сгенерировал случайные числа в количестве 512 на 512.
Но если компилятор TinyCC отработал благополучно, то с Хаскеллем возникли проблемы.
Компилятор GHC выдал сообщение:
Попытка выделить более 129024 байт. В настоящее время это невозможно из-за ограничений генератора кода GHC.
Предложение: читайте данные из файла вместо больших статических структур данных в коде.
Вот это да! На что ещё годен Хаскелл, кроме защиты диссертаций?!
Десятки британских учёных защитили на нём учёные степени, а довести до ума компилятор — руки не дошли.
А между тем, компилятор TinyCC написал одиночка и проблем с объёмом статических данных в нём не наблюдается.
Опустился до матрицы 128x128, тогда компиляция прошла успешно.
Но после запуска программка выдала: «Infinity». На этом желание сравнивать иссякло.
Опубликовано: 2022.01.01, последняя правка: 2022.02.10 20:49
Отзывы
✅ 2022/05/14 13:13, MihalNik #0
Но раз не побоялись выложить код на всеобщее обозрение, значит он приемлем для программистов на Хаскелле. Ничего это не значит. Выложено в открытый доступ может быть просто потому, что самому не нужно. А вдруг, кому-то будет интересно? Или для галочки по требованию образовательного учреждения. А нелинейный рост соотношения, может говорить как о неправильной реализации испытываемого решения в рамках данного языка, так и о неправильной реализации компилятора или необходимости его доработки.кандидат физико-математических наук, доцент Как будто кандидат наук не может писать программ уровня студента. Где толпы ленивых студентов на форумах, умоляющих решить им горящие до завтра задачки на Хаскелле? Нет их, а значит и преподавания Хаскелла по сути нет, как нет или почти нет грамотных специалистов, умеющих с ним работать.
А может некоторые наши студенты делают ЯП и получше некоторых британских ученых. Просто так может получиться, когда что-то делается для себя, из любопытсва, а не ради должностей и зарплат.✅ 2022/05/14 19:29, Автор сайта #1
Или для галочки по требованию образовательного учреждения. Ну что Вы. В этом трудно заподозрить человека, который бесплатно отвечает на вопросы на форумах в выходные дни совершенно незнакомым людям. Который, к тому же, написал собственный бесплатный транслятор Лиспа.Где толпы ленивых студентов на форумах, умоляющих решить им горящие до завтра задачки на Хаскелле? Нет их, а значит и преподавания Хаскелла по сути нет, как нет или почти нет грамотных специалистов, умеющих с ним работать. Ну в этом Вы правы. Об уровне соответствующих специалистов можно косвенно судить по уровню учебников. Они не ахти какие, значит их особо-то и некому писать.✅ 2022/05/15 08:55, MihalNik #2
Ну что Вы. В этом трудно заподозрить человека Суть в том, что нельзя сделать выводы на основе полученных замеров из-за большого кол-ва неопределенностей.в целом отечественный компилятор PL/1 выглядит достойно на импортном фоне Было бы очень здорово провести более глубокое сравнение с разными компиляторами языка C на разных машинах и для большего числа задач.✅ 2022/05/15 14:50, Автор сайта #3
Было бы очень здорово провести более глубокое сравнение с разными компиляторами языка C на разных машинах Да, хорошая мысль. Неплохо бы разработать набор различных заданий, чтобы их реализовать на разных языках и компиляторах. Набор должен быть достаточно разнообразным, чтобы можно было давать оценки скорости работы как плавающей, так и фиксированной арифметики, строк и всего прочего. Подозреваю, что такой набор уже где-то существует, но чтоб его найти, нужна достаточная степень любопытства :) Добавить свой отзыв
Написать автору можно на электронную почту mail(аt)compiler.su
|