Эффективная ленивая генерация ByteString на примере случайной ByteString
Кажется, есть некоторые препятствия для эффективной ленивых ByteString
поколение рекурсией. Чтобы продемонстрировать это, выбранная задача состоит в том, чтобы сделать ленивую случайную ByteString
, (Генерация случайных чисел - просто разумная операция, т. Е. Заполнитель для любой другой рекурсии, которая может представлять интерес.)
Вот две попытки создать случайный ленивый ByteString
фиксированной длины n
, Они выделяют огромное количество кучи. Сначала немного импорта:
import qualified Data.ByteString.Lazy as BSL
import Data.Word8
import System.Random
Теперь функция, которая использует cons
:
lazyRandomByteString1 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString1 n g = fst3 $ iter (BSL.empty, n, g) where
fst3 (a, _, _) = a
iter (bs', n', g') =
if n' == 0 then (bs', 0, g')
else iter (w `BSL.cons` bs', n'-1, g'') where
(w, g'') = random g' :: (Word8, StdGen)
То же самое, просто используя unfoldr
короче, но почти так же плохо, как и выше:
lazyRandomByteString2 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString2 n g = BSL.unfoldr f (n, g) where
f :: (Int, StdGen) -> (Int, StdGen)
f (n', g') =
if n' == 0 then Nothing
else Just (w, (n'-1, g'')) where
(w, g'') = random g' :: (Word8, StdGen)
В пределах того, что предусмотрено Data.ByteString.Lazy
это все доступные варианты создания ByteStrings
рекурсией.
Затем перейдите к Data.ByteString.Lazy.Builder
был построен, чтобы строить ленивый ByteStrings
Конечно, это должно быть более эффективным:
import Data.ByteString.Lazy.Builder (Builder, toLazyByteString, word8)
lazyRandomByteString3 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString3 n g = toLazyByteString builder where
builder :: Builder
builder = fst3 $ iter (mempty, n, g) where
fst3 (a, _, _) = a
iter :: (Builder, Int, StdGen) -> (Builder, Int, StdGen)
iter (b, n', g') =
if n' == 0 then (b, 0, g')
else iter (b <> (word8 w), n'-1, g'') where
(w, g'') = random g' :: (Word8, StdGen)
Но это не так.
Builder
действительно должно быть в состоянии сделать это эффективно, не так ли? Что не так с lazyRandomByteString3
?
Исходный код находится на github.