Обновление 2 : Этот вопрос является поддельным. Приношу извинения. Я добавил некоторый код для печати массива, пропуская остальную часть логики моей программы, и это почти мгновенно. Я думал, что медленная печать массива должна была быть медленной {что-то}, что было лениво вычислено после того, как была введена функция массива печати.
Обновление 1 : приведенный ниже фрагмент неверно воспроизводит проблему с производительностью в моей исходной проблеме. Я, должно быть, неправильно объяснил источник медлительности, либо из-за неверного отслеживания ленивых выражений, либо из-за некоторых других изменений, которые я сделал, когда вытащил небольшой фрагмент из более крупной программы. Я постараюсь создать автономное воспроизведение медленной обработки.
Резюме:
Форматирование распакованного массива Int32 в строку и вывод результирующего ~ 4 МБ текста на диск неэффективен, примерно 1 минута для печати 1 миллиона значений (60K циклов ЦП на значение). Зачем? Можно ли сделать это быстрее?
подробности:
Запуск в виде скомпилированной программы с флагом компилятора "-O2". GHC 7.0.4, платформа Haskell 2011.04, Windows 7 x64.
У меня есть программа на Haskell, которая создает массив размером от 100K до 1 миллиона Int32
значений.
Значения Int32
на самом деле Int8
значения из 4-х кортежей (Int8, Int8, Int8, Int8)
, упакованные в Int32
в (возможно, ошибочной) попытке повышения эффективности.
Я использую STUArray (но это может быть плохим выбором) для хранения и изменения массива.
В определенные моменты моей программы я печатаю массив на диск в следующем виде:
byte byte byte ...
, где каждый байт является ASCII-представлением десятичного значения байта (от «0» до «255»). Пример: * * тысяча тридцать пять
0 255 128 5 31 ...
Моя проблема заключается в том, что действие ввода-вывода при печати массива в Handle
выполняется медленно: Требуется около минуты для форматирования печати ~ 1 миллиона байтов в текст на дескрипторе файла , на современном Процессор i5 с тактовой частотой 3,3 ГГц и диск SSD.
Мой код для печати в основном такой:
импорт Data.Array.Unboxed
импорт System.IO
импорт Contol.Monad
импорт данных. Биты
ручка printArray frozenArray = mapM _ ( hPutStr ручка. ShowPacked. (FrozenArray!)) [0..arrayLength]
showPacked x = (' ':) . (shows $ (shift x (-24)) .&. 255)
. (' ':) . (shows $ (shift x (-16)) .&. 255)
. (' ':) . (shows $ (shift x (-8)) .&. 255)
. (' ':) . (shows $ x .&. 255)
$ ""
Есть ли лучший способ?
Что может быть источником проблемы? У меня есть несколько догадок (в порядке убывания вероятности):
- Форматирование каждого Int32 с моим кодом неэффективно.
- mapM_ для массива с (!) Неэффективным.
- Вызов hPutStr миллион раз неэффективен.
- 1 минута для печати 1 миллиона значений на самом деле эффективна.
Предупреждение о потенциальной красной сельди: Существует некоторый риск того, что задержка, которую я вижу, связана с отложенными вычислениями, которые вызываются только при печати, а не вызваны самим форматированием / печатью, но я так не думаю, потому что даже когда Я печатаю массив в первой итерации (после создания исходного пустого массива), он все еще медленный. И я могу наблюдать, как выходной файл медленно растет, поэтому после печати первого байта происходит большая работа, даже с использованием строгого распакованного массива.