gpt4 book ai didi

haskell - 如何对自定义数据类型进行内存映射 IO?

转载 作者:行者123 更新时间:2023-12-02 15:07:22 25 4
gpt4 key购买 nike

设置

我最近实现了基于 mmap 的文件读取,并直接遇到了奇怪的行为。相关代码为:

-- | map whole aedat file into memory and return it as a vector of events
-- TODO what are the finalizing semantics of this?
mmapAERData :: S.Storable a => FilePath -> IO (S.Vector (AER.Event a))
mmapAERData name = do
-- mmap file into memory and find the offset behind the header
bs <- dropHeader <$> mmapFileByteString name Nothing
-- some conversion is necessary to get the 'ForeignPtr' from
-- a 'ByteString'
B.unsafeUseAsCString bs $ \ptr -> do
fptr <- newForeignPtr_ ptr
let count = B.length bs `div` 8 -- sizeof one event
return $ S.unsafeFromForeignPtr0 (castForeignPtr fptr) count

→ code in context

一些解释:AEDat 格式基本上是两个 Word32 的长列表。一个编码地址,另一个编码时间戳。在此之前,我将一些标题文本放入 dropHeader 函数中。如果绝对必要,我可以直接在 ForeignPtr 上执行此操作,但我更喜欢使用适用于 ByteStrings 的通用函数。

可以找到Storable实例herehere 。我不确定这里的对齐方式,但我怀疑 8 的对齐方式应该是正确的。

问题

读取数据效果很好,但一段时间后内存似乎会以某种方式损坏:

>>> es <- DVS.mmapDVSData "dataset.aedat" 
>>> es S.! 1000
Event {address = Address {polarity = D, posX = 6, posY = 50}, timestamp = 74.771407s}
>>> :type es
es :: S.Vector (DVS.Event DVS.Address)
>>> _ <- evaluate (V.convert es :: V.Vector (DVS.Event DVS.Address))
>>> es S.! 1000
Event {address = Address {polarity = D, posX = 0, posY = 44}, timestamp = 0s}

显然,访问es的所有元素会以某种方式破坏我的内存。或者垃圾收集器回收它?不管怎样,这都很奇怪。对此我能做什么?

最佳答案

mmapFileByteString执行 mmap ,这会创建一个 ForeignPtr ,并坚持ForeignPtr进入ByteStringunsafeUseAsCString强制 ForeignPtr进入Ptr ,然后从中创建一个新的 ForeignPtr 。然后你就捕获那一秒ForeignPtr并将其与 S.unsafeFromForeignPtr0 一起使用创建一个向量。

有两个ForeignPtr s 指向同一内存是不行的。 GHC 运行时将它们视为两个单独的对象。毕竟引用了 ByteString消失了,其 ForeignPtr 的终结器将被调用,释放 mmap并回收底层内存。剩下第二个ForeignPtr指向无效区域。

这里的解决方案是使用 Data.ByteString.Internal.toForeignPtr 提取并重新使用 ForeignPtr来自ByteString 。替换unsafeUseAsCString用这个阻止:

let (fptr,offset,len) = Data.ByteString.Internal.toForeignPtr bs
-- it might be worthwhile to assert that offset == 0
let count = len `div` 8
return $ S.unsafeFromForeignPtr0 (castForeignPtr fptr) count

恕我直言,真正的解决方案是根本不要摆弄所有这些东西。只需按照惯例将文件读入 ByteString ,从中取出 8 字节子字符串并手动将它们转换为 Event s。这一切mmapForeignPtr事情是危险的,而且并不比安全、正确地做事快多少。如果您想要绝对最快的性能而不考虑安全性,请使用 C 进行编程。

关于haskell - 如何对自定义数据类型进行内存映射 IO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31476005/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com