我什么时候使用ByteString,什么时候不使用?

时间:2011-05-11 23:49:28

标签: haskell io performance bytestring

我对SPOJ上的PRIME1问题进行了相当差的尝试。我发现使用ByteString 确实帮助性能阅读问题文本。但是,使用ByteString写出结果实际上比使用Prelude函数稍慢。我试图弄清楚我做错了,或者这是否是预期的。

我使用(putStrLn.show)和ByteString等效三种方式进行了分析和计时:

  1. 我测试每个候选人是否有 是素数。如果是这样,我将其添加到列表中 并用(putStrLn。 显示)
  2. 我列出了所有素数 并使用。写出列表 (putStrLn.unlines。show)
  3. 我列出了所有素数 并使用。写出列表 map(putStrLn。show)
  4. 我希望数字2和3在一个函数中构建一个列表并在另一个函数中使用它时执行速度较慢。通过在生成数字时打印数字,我避免为列表分配任何内存。另一方面,每次调用putStrLn时都要进行一次调用系统调用。对?所以我测试了,#1实际上是最快的。

    使用选项#1和Prelude([Char])功能实现了最佳性能。我希望我的最佳表现是ByteString的选项#1,但事实并非如此。我只使用懒惰的ByteStrings,但我认为这不重要。会吗?

    有些问题:

    • 你会期待ByteStrings吗? 写一堆更好的表现 整数到stdout?
    • 我错过了一种模式 生成并写出答案 这将导致更好 性能
    • 如果我只写出数字 文本,何时,如果有的话 有利于使用ByteString?

    我的工作假设是,如果你没有将它们与其他文本组合,用ByteString写出Integer会更慢。如果您将Integers与[Char]结合使用,那么使用ByteStrings可以获得更好的性能。即,ByteString重写:

    putStrLn $ "the answer is: " ++ (show value)
    

    将比上面写的版本快得多。这是真的吗?

    感谢阅读!

2 个答案:

答案 0 :(得分:21)

使用bytestrings进行批量输入通常会更快,因为数据密集,从磁盘到内存的数据就更少了。

将数据写为输出但是有点不同。通常,您要序列化结构,生成许多小写入。因此,在这种情况下,字节串的密集,批量写入对您没有多大帮助。即使是常规Strings,也会在增量输出时合理地进行。

然而,一切都不会丢失。我们可以通过在内存中有效地构建字节串来恢复快速批量写入。这种方法由各种*-builder包采用:

我们不是将值转换为许多微小的字节串,而是一次一个地写出来,而是将转换流转换为不断增长的缓冲区,然后将缓冲区写入一个大块。与字符串IO相比,这会导致更少的IO开销和性能改进(通常是显着的)。

这种方法是由例如Haskell中的Web服务器,或高效的HTML系统,blaze

此外,即使使用批量写入,性能也取决于类型和字节串之间的任何转换函数的效率。对于Integer,您可能只是将内存中的位模式复制到输出,或者通过一些低效的解码器。因此,您有时需要考虑一下您正在使用的编码函数的质量,而不仅仅是使用Char / String还是bytestring IO。

答案 1 :(得分:7)

请注意,效果不是ByteStringString之间的主要区别。前者用于二进制数据,后者用于Unicode文本。如果您有二进制数据,请使用ByteString,如果您有Unicode文本,请使用text package中的Text类型。