IOUArray to ByteSring,尽快

fel*_*xgb 5 arrays haskell ghc bytestring websocket

我需要Word8非常快速地改变固定大小数组中的元素.为此我正在使用IOUArray.我需要通过websocket连接发送这个数组.sendBinaryDatawebsockets包中的功能需要a ByteString.我需要从一个表示转换为另一个表示.我目前正在使用此功能:

arrayToBS :: IOUArray Int Word8 -> IO (BS.ByteString)
arrayToBS = (fmap BS.pack) . getElems
Run Code Online (Sandbox Code Playgroud)

此函数将数组的元素转换为[Word8]将列表打包成字节字符串之前,并且从分析中我可以看到它非常慢.我想知道是否有办法加速这个功能,或者可能直接通过websocket连接发送数组?

我目前使用的数组是:

size = 1000;
numBytes = size * size * 4

newBuffer :: IO (IOUArray Int Word8)
newBuffer = newArray (0, numBytes) 200 :: IO (IOUArray Int Word8)
Run Code Online (Sandbox Code Playgroud)

除绩效报告外:

COST CENTRE MODULE SRC                        %time %alloc

arrayToBS   Lib    src/Lib.hs:28:1-37          88.1   99.0
newBuffer   Lib    src/Lib.hs:(23,1)-(25,12)    9.9    0.8
Run Code Online (Sandbox Code Playgroud)

理想情况下arrayToBS比创建数组要快得多.如果我size改为100:

COST CENTRE         MODULE                          SRC                                                %time %alloc

arrayToBS           Lib                             src/Lib.hs:21:1-37                           100.0   86.1
mkEncodeTable.table Data.ByteString.Base64.Internal Data/ByteString/Base64/Internal.hs:105:5-75    0.0    8.0
mkEncodeTable.ix    Data.ByteString.Base64.Internal Data/ByteString/Base64/Internal.hs:104:5-43    0.0    1.1
Run Code Online (Sandbox Code Playgroud)

Ale*_*lec 2

免责声明:我对这些低级原语不太熟悉,因此在某些情况下这可能不安全。


您至少需要复制一次数据,因为正如 @user2407038 所说,存储在 an 中的基础数据IOUArray是一个未固定的数组,因此我们不能指望 GHC 不移动数组。然而,相反的方向(ByteStringIOArray)无需副本也是可能的。

{-# LANGUAGE UnboxedTuples, MagicHash #-}

import Data.ByteString.Internal (ByteString(..))
import Data.Array.IO.Internals  (IOUArray(..))
import Data.Array.Base          (STUArray(..))
import Data.Word                (Word8)

import Foreign.ForeignPtr (mallocForeignPtrBytes, withForeignPtr)
import GHC.IO             (IO(..))
import GHC.Exts           (copyMutableByteArrayToAddr#, Ptr(..), Int(..))

arrayToBS :: IOUArray Int Word8 -> IO ByteString
arrayToBS (IOUArray (STUArray _ _ n@(I# n') mutByteArr)) = do
  bytes <- mallocForeignPtrBytes n
  withForeignPtr bytes $ \(Ptr addr) -> IO $ \state ->
    (# copyMutableByteArrayToAddr# mutByteArr 0# addr n' state, () #)
  pure (PS bytes 0 n)
Run Code Online (Sandbox Code Playgroud)

下面是对此工作的测试(请记住,ascii 代码是'A'65

ghci> iou <- newListArray (-2,9) [65,67..] :: IO (IOUArray Int Word8)
ghci> arrayToBS iou
"ACEGIKMOQSUW"
Run Code Online (Sandbox Code Playgroud)