将 Data.ByteString.Lazy 转换为 CStringLen 的最有效方法
Posted
技术标签:
【中文标题】将 Data.ByteString.Lazy 转换为 CStringLen 的最有效方法【英文标题】:Most efficient way of converting a Data.ByteString.Lazy to a CStringLen 【发布时间】:2020-02-15 06:26:37 【问题描述】:我需要将一些数据编码为 JSON,然后使用 hsyslog 推送到 syslog。两个相关函数的类型分别是:
Aeson.encode :: a -> Data.ByteString.Lazy.ByteString
System.Posix.Syslog.syslog :: Maybe Facility
-> Priority
-> CStringLen
-> IO ()
转换Lazy.ByteString -> CStringLen
的最有效方法(速度和内存)是什么?我找到了Data.ByteString.Unsafe
,但它只适用于ByteString
,不适用于Lazy.ByteString
?
我可以贴一个unsafeUseAsCStringLen . Data.String.Conv.toS
并收工吗?效率方面是否正确?
【问题讨论】:
【参考方案1】:我想我会使用Data.ByteString.Lazy.toStrict
代替toS
,以避免额外的包依赖。
无论如何,您找不到比以下更有效的方法:
unsafeUseAsCStringLen (toStrict lbs) $ \cstrlen -> ...
一般来说,toStrict
是一个“昂贵”的操作,因为懒惰的ByteString
通常由一堆“块”组成,每个“块”都包含一个严格的ByteString
,而且不一定还加载到内存中。 toStrict
函数必须强制所有严格的ByteString
块进入内存,并确保在应用无复制unsafeUseAsCStringLen
之前将它们复制到严格的ByteString
所需的单个连续块中。
然而, toStrict
处理一个懒惰的ByteString
,它最好由一个块组成,无需任何复制。
实际上,aeson
使用高效的Data.ByteString.Builder
创建 JSON,如果 JSON 相当小(我认为小于 4k),它将构建一个单块惰性ByteString
。在这种情况下toStrict
是零拷贝,unsafeUseAsCStringLen
是零拷贝,整个操作基本是免费的。
但请注意,在您的应用程序中,您将字符串传递给系统记录器,担心此操作的效率是疯狂的。我的猜测是,您甚至需要数千次复制操作才能降低整体操作的性能。
【讨论】:
"不一定还加载到内存中。" -- 你为什么这么说?这是否意味着惰性 ByteStrings 在后台进行惰性 IO?如果我调用BSL.readFile
,它不会将所有内容加载到内存中吗?如果我调用BSL.readFile
,删除文件,然后尝试访问读取的整个惰性字节串会发生什么?
你回答的最后两段解决了我原来的问题。谢谢你有见地的回复。有时间请看能不能解释一下***.com/questions/60236427/…
是的,BSL.readFile
在后台执行惰性 I/O。原则上它可以执行严格的 I/O,但是返回一个懒惰的 BS 就没有多大意义了。尽管如此,如果您使用BSL.readFile
,然后删除文件并尝试读取内容,它仍然可以正常工作,但这是因为文件句柄保持打开状态,并且仍然可以从已删除文件的打开句柄中读取数据. (嗯,某些网络文件系统除外。)但是,如果您破坏性地修改文件(覆盖或截断它),那么这些更改通常会反映在延迟读取的值中。以上是关于将 Data.ByteString.Lazy 转换为 CStringLen 的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章
Haskell语言学习笔记(49)ByteString Text
将 A 转换为 1 B 转换为 2 ... Z 转换为 26,然后将 AA 转换为 27 AB 转换为 28(Excel 中列引用的列索引)