Haskell - чтение всей Lazy ByteString
Контекст: у меня есть функция, определенная в библиотеке toXlsx :: ByteString -> Xlsx
(это ByteString из Data.ByteString.Lazy)
Теперь для выполнения определенных операций я определил определенные функции, которые работают с одним и тем же файлом, поэтому я хотел бы открыть, прочитать и преобразовать файл в Xlsx один раз и сохранить его в памяти для работы с ним.
Прямо сейчас я читаю файл как bs <- Data.ByteString.Lazy.readfile file
и в конце делаю Data.ByteString.Lazy.length bs 'seq' return value
,
Есть ли способ использовать эту функцию и сохранить файл в памяти в целом для его повторного использования?
1 ответ
Обратите внимание, что, как работает ленивая строка тестирования, содержимое файла не будет прочитано до тех пор, пока оно не будет "использовано", но после прочтения оно останется в памяти для любых последующих операций. Единственный способ их удаления из памяти - это сборка мусора, поскольку ваша программа больше не имеет доступа к ним.
Например, если вы запустите следующую программу для большого файла:
import qualified Data.ByteString.Lazy as BL
main = do
bigFile <- BL.readFile "ubuntu-14.04-desktop-amd64.iso"
print $ BL.length $ BL.filter (==0) bigFile -- takes a while
print $ BL.length $ BL.filter (==255) bigFile -- runs fast
первое вычисление фактически прочитает весь файл в память, и оно будет сохранено там для второго вычисления.
Я думаю, что это само по себе не слишком убедительно, поскольку операционная система также будет кэшировать файл в память, и в итоге будет трудно определить разницу во времени между тем, как Haskell считывает файл из кэша операционной системы для каждого вычисления и сохраняет это в памяти через все вычисления. Но если вы запустили какое-то профилирование кучи для этого кода, вы обнаружите, что первая операция загружает весь файл в "закрепленные" строки байтов и что распределение остается постоянным при последующих операциях.
Если вас беспокоит то, что вы хотите, чтобы весь файл был прочитан в начале, даже если первой операции не нужно читать все это, чтобы не было никаких последующих задержек при чтении дополнительных частей файла, тогда ваш seq
решение на основе, вероятно, хорошо. Кроме того, вы можете прочитать весь файл как строгую строку, а затем преобразовать его, используя fromStrict
- эта операция является мгновенной и не копирует никаких данных. (В отличие от toStrict
, который стоит дорого и копирует данные.) Так что это будет работать:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
main = do
-- read strict
bigFile <- BS.readFile "whatever.mov"
-- do strict and lazy operations
print $ strictOp bigFile
print $ lazyOp (BL.fromStrict bigFile)