将 Data.ByteString.Lazy 转换为 CStringLen 的最有效方法

Most efficient way of converting a Data.ByteString.Lazy to a CStringLen

我需要将一些数据编码为 JSON,然后使用 hsyslog 将其推送到系统日志。两个相关函数的类型是:

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 就到此为止吗?它会提高效率吗?

我想我会用 Data.ByteString.Lazy.toStrict 代替 toS,以避免额外的包依赖。

无论如何,您找不到比以下更有效的方法:

unsafeUseAsCStringLen (toStrict lbs) $ \cstrlen -> ...

一般来说,toStrict是一个"expensive"操作,因为一个惰性的ByteString一般会由一堆"chunks"组成,每个由一个严格的ByteString 并且不一定还加载到内存中。 toStrict 函数必须强制所有严格 ByteString 块进入内存,并确保在非复制 [=19] 之前按照严格 ByteString 的要求将它们复制到单个连续块中=] 已应用。

然而, toStrict 处理惰性 ByteString,它由单个块组成,没有任何复制。

实际上,aeson 使用高效的 Data.ByteString.Builder 来创建 JSON,如果 JSON 相当小(我认为小于 4k),它将构建一个单块惰性 ByteString。这样的话,toStrict就是零拷贝,unsafeUseAsCStringLen就是零拷贝,整个操作基本是免费的。

但请注意,在您的应用程序中,您将字符串传递给 syslogger,担心此操作的效率是疯狂的。我的猜测是,您需要数千次复制操作才能影响整体操作的性能。