0

一些代码的分析表明,大约 65% 的时间我都在下面的代码中。

它所做的是使用 Data.Binary.Get monad 遍历一个字节串来寻找终止符。如果检测到 0xff,则检查下一个字节是否为 0x00。如果是,它会丢弃 0x00 并继续。如果它不是 0x00,那么它会丢弃两个字节,并将生成的字节列表转换为字节串并返回。

有什么明显的优化方法吗?我看不到它。

parseECS = f [] False
    where
    f acc ff = do
        b <- getWord8
        if ff
            then if b == 0x00
                then f (0xff:acc) False
                else return $ L.pack (reverse acc)
            else if b == 0xff
                then f acc True
                else f (b:acc) False
4

2 回答 2

1

错误修复

似乎这里可能有一个错误。如果您在找到 0xff 而不是 0x00 序列之前到达字节流的末尾,则会引发异常。这是您的函数的修改版本:

parseECS :: Get L.ByteString
parseECS = f [] False
  where
    f acc ff = do
      noMore <- isEmpty
      if noMore
         then return $ L.pack (reverse acc)
         else do
           b <- getWord8
           if ff
              then
                if b == 0x00
                   then f (0xff:acc) False
                   else return $ L.pack (reverse acc)
              else
                if b == 0xff
                   then f acc True
                   else f (b:acc) False

优化

我没有做任何分析,但这个功能可能会更快。反转长列表是昂贵的。我不确定有多懒惰getRemainingLazyByteString。如果它太严格,这可能对你不起作用。

parseECS2 :: Get L.ByteString
parseECS2 = do
    wx <- liftM L.unpack $ getRemainingLazyByteString
    return . L.pack . go $ wx
  where
    go []             = []
    go (0xff:0x00:wx) = 0xff : go wx
    go (0xff:_)      = []
    go (w:wx)         = w : go wx
于 2010-03-20T20:02:09.257 回答
0

如果问题出在“反向”中,您可以使用“lookAhead”扫描位置,然后返回并重建新字符串

parseECS2 :: Get L.ByteString
parseECS2 = do
    let nextWord8 = do
            noMore <- isEmpty
            if noMore then return Nothing
                      else liftM Just getWord8

    let scanChunk !n = do
            b <- nextWord8
            case b of
                Just 0xff -> return (Right (n+1))
                Just _ -> scanChunk (n+1)
                Nothing -> return (Left n)

    let readChunks = do
            c <- lookAhead (scanChunk 0)
            case c of
                Left n -> getLazyByteString n >>= \blk -> return [blk]
                Right n -> do
                    blk <- getLazyByteString n
                    b <- lookAhead nextWord8
                    case b of
                        Just 0x00 -> skip 1 >> liftM (blk:) readChunks
                        _ -> return [L.init blk]

    liftM (foldr L.append L.empty) readChunks
于 2010-03-21T16:03:51.780 回答