Эффективное разделение каналов для строгой строки байтов

Это продолжение этого более раннего вопроса. У меня есть источник канала (от Network.HTTP.Conduit), который является строгим ByteString. Я хотел бы рекомбинировать их в более крупные фрагменты (для отправки по сети другому клиенту после еще одного кодирования и преобразования в ленивую строку байтов). Я написал chunksOfAtLeast канал, основанный на ответе на вопрос выше, который, похоже, работает довольно хорошо. Мне интересно, есть ли дальнейшие возможности для улучшения его производительности.

import Data.Conduit as C
import Control.Monad.IO.Class
import Control.Monad
import Data.Conduit.Combinators as CC
import Data.Conduit.List as CL
import Data.ByteString.Lazy as LBS hiding (putStrLn)
import Data.ByteString as BS hiding (putStrLn)

chunksOfAtLeast :: Monad m => Int -> Conduit BS.ByteString m BS.ByteString
chunksOfAtLeast chunkSize =
    loop
  where
    loop = do
        bs <- takeE chunkSize =$= ((BS.concat . ($ [])) <$> CL.fold (\front next -> front . (next:)) id)
        unless (BS.null bs) $ do
            yield bs
            loop

main = do
  yieldMany ["hello", "there", "world!"] $$ chunksOfAtLeast 8 =$ CL.mapM_ Prelude.print

person Sal    schedule 22.06.2016    source источник
comment
Что говорит профайлер?   -  person jamshidh    schedule 23.06.2016
comment
Я протестировал это через RTS -s вместо микробенчмаркинга критерия. Я получаю пропускную способность около 30 МБ/с на ядро ​​(на среднем экземпляре AWS m3). Мне кажется вполне прилично. Просто любопытно, есть ли какие-нибудь другие трюки с производительностью, которые я мог бы использовать. Или если это настолько хорошо, насколько это возможно.   -  person Sal    schedule 23.06.2016


Ответы (1)


Чтобы добиться оптимальной производительности, всегда нужно что-то пробовать и сравнивать, поэтому я не могу с уверенностью сказать, что предлагаю вам что-то более эффективное. Тем не менее, объединение небольших фрагментов данных в более крупные фрагменты является основной целью конструкторы, поэтому их использование может оказаться более эффективным. Вот пример:

{-# LANGUAGE OverloadedStrings #-}
import Conduit
import Data.ByteString (ByteString)
import Data.ByteString.Builder (byteString)
import Data.Conduit.ByteString.Builder

bufferChunks :: Conduit ByteString IO ByteString
bufferChunks = mapC byteString =$= builderToByteString

main :: IO ()
main = yieldMany ["hello", "there", "world!"] $$ bufferChunks =$ mapM_C print
person Michael Snoyman    schedule 23.06.2016