我需要非常快速地更改Word8
的固定大小数组中的元素。为此,我使用了IOUArray
。我需要通过websocket连接发送此数组。来自websockets软件包的sendBinaryData
函数需要一个ByteString
。我需要从一种表示转换为另一种表示。我目前正在使用此功能:
arrayToBS :: IOUArray Int Word8 -> IO (BS.ByteString)
arrayToBS = (fmap BS.pack) . getElems
在将该列表打包为字节串之前,此函数将数组的元素转换为
[Word8]
,从分析中我可以看到它相当慢。我想知道是否有办法加快此功能,或者可能直接通过websocket连接发送阵列?我当前使用的数组是:
size = 1000;
numBytes = size * size * 4
newBuffer :: IO (IOUArray Int Word8)
newBuffer = newArray (0, numBytes) 200 :: IO (IOUArray Int Word8)
效果报告中的一个异常(exception):
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
理想情况下,
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
最佳答案
免责声明:我对这些低级原语不是很熟悉,因此在某些情况下这可能是不安全的。
您至少需要将数据复制一次,因为正如@ user2407038所述,存储在IOUArray
中的基础数据是未固定的数组,因此我们不能指望GHC不会移动该数组。但是,没有副本也可以使用相反的方向(ByteString
到IOArray
)。
{-# 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)
这是这项工作的测试(请记住
'A'
的ascii代码是65
):ghci> iou <- newListArray (-2,9) [65,67..] :: IO (IOUArray Int Word8)
ghci> arrayToBS iou
"ACEGIKMOQSUW"
关于arrays - 尽快将IOUArray转换为ByteSring,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45784663/