我需要非常快速地更改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不会移动该数组。但是,没有副本也可以使用相反的方向(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)

这是这项工作的测试(请记住'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/

10-12 04:48