Подтвердить что ты не робот

Когда я использую ByteString, а когда нет?

Я делал довольно плохие попытки проблемы PRIME1 на SPOJ. Я обнаружил, что использование ByteString действительно помогло производительности для чтения в тексте проблемы. Однако использование ByteString для вывода результатов на самом деле немного медленнее, чем использование функций Prelude. Я пытаюсь понять, если я делаю это неправильно, или если это ожидается.

Я провел профилирование и время, используя (putStrLn.show) и эквиваленты ByteString тремя разными способами:

  • Я проверяю каждого кандидата, чтобы узнать, является простым. Если это так, я добавляю его в список и напишите его (putStrLn. шоу)
  • Я делаю список всех простых чисел и запишите список, используя (putStrLn. unlines. show)
  • Я делаю список всех простых чисел и запишите список, используя map (putStrLn. show)

Я ожидал, что числа 2 и 3 будут выполняться медленнее, когда вы создаете список в одной функции и потребляете его в другом. При печати чисел по мере их создания я избегаю выделения какой-либо памяти для списка. С другой стороны, вы вызываете системный вызов вызова с каждым вызовом putStrLn. Правильно? Итак, я тестировал, а №1 был самым быстрым.

Наилучшая производительность была достигнута с опциями # 1 и Prelude ([ Char]). Я ожидал, что моя лучшая производительность будет вариантом № 1 с ByteString, но это было не так. Я использовал только ленивый ByteStrings, но я не думал, что это имеет значение. Будет ли это?

Некоторые вопросы:

  • Вы ожидаете, что ByteStrings лучше работать для написания Целые числа в stdout?
  • Я пропустил шаблон пути генерировать и записывать ответы что приведет к улучшению производительность?
  • Если я только пишу цифры, текст, когда, если когда-либо, есть извлечь выгоду из использования ByteString?

Моя рабочая гипотеза заключается в том, что запись Integer с ByteString происходит медленнее, если вы не комбинируете их с другим текстом. Если вы комбинируете целые числа с [ Char], вы получите лучшую производительность, работающую с ByteStrings. I.e., ByteString переписывает:

putStrLn $ "the answer is: " ++ (show value)

будет намного быстрее, чем версия, написанная выше. Это правда?

Спасибо за чтение!

4b9b3361

Ответ 1

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

Запись данных как результат, однако, немного отличается. Как правило, вы сериализуете структуру, генерируя много мелких записей. Таким образом, плотные, объемные записи об ошибках не помогут вам в этом случае. Даже обычный Strings будет делать разумно при инкрементном выходе.

Однако все не потеряно. Мы можем восстанавливать быстрые массивные записи, эффективно наращивая bytestrings в памяти. Этот подход используется различными пакетами *-builder:

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

Такой подход применяется, например, webservers в Haskell или эффективная система HTML, blaze.

Кроме того, производительность даже при объемной записи будет зависеть от эффективности любой функции преобразования, которую вы имеете между вашими типами и байтами. Для Integer вы можете просто копировать битовый паттерн в памяти для вывода или вместо этого использовать неэффективный декодер. В результате вам иногда приходится немного думать о качестве используемой функции кодирования, а не только о том, следует ли использовать Char/String или bytestring IO.

Ответ 2

Обратите внимание, что производительность не является основным различием между ByteString и String. Первый - для двоичных данных, а последний - для текста Unicode. Если у вас есть двоичные данные, используйте ByteString, если у вас есть текст в Юникоде, используйте тип Text из текстового пакета .