为什么使用Data.Text构建Haskell字符串如此缓慢

3
所以我有一个位置类。
data Location = Location {
    title :: String
  , description :: String
  }

instance Show Location where
  show l = title l ++ "\n"
         ++ replicate (length $ title l) '-' ++ "\n"
         ++ description l

接着我改用了Data.Text

data Location = Location {
    title :: Text
  , description :: Text
  }

instance Show Location where
  show l = T.unpack $
    title l <> "\n"
    <> T.replicate (T.length $ title l) "-" <> "\n"
    <> description l

使用 Criterion,我对 StringData.Text 实现的 show 函数所需时间进行了基准测试:

benchmarks = [ bench "show" (whnf show l) ]
  where l = Location {
                title="My Title"
              , description = "This is the description."
              }
String的实现只需要34纳秒,而Data.Text的实现要慢近六倍,需要170纳秒。
我该如何让Data.Text的速度与String一样快呢? 编辑:愚蠢的错误 我不确定怎么会出现这种情况,但我无法复制最初的速度差异:现在对于String和Text,我分别得到28ns和24ns。
对于更具攻击性的bench "length.show" (whnf (length . show) l)基准测试,对于String和Text,我分别得到467ns和3954ns。
如果我使用一个非常基本的惰性构建器,没有重复的破折号。
import qualified Data.Text.Lazy.Builder as Bldr

instance Show Location where
  show l = show $
    Bldr.fromText (title l) <> Bldr.singleton '\n'
  --  <> Bldr.fromText (T.replicate (T.length $ title l) "-") <> Bldr.singleton '\n'
    <> Bldr.fromText (description l)

当我尝试使用原始的普通show基准测试时,得到了19ns。现在这有点错误,因为使用show将构建器转换为字符串会转义换行符。如果我将其替换为LT.unpack $ Bldr.toLazyText,其中LTData.Text.Lazy的限定导入,则我会得到192ns。

我在Mac笔记本电脑上进行测试,我怀疑我的时间测量结果可能会受到机器噪声的干扰。感谢您的指导。


1
Data.Text.Lazy.Builder:高效构建惰性文本值。 - user2407038
2个回答

3

虽然不能让它更快,但可以加速一些。

附加

Text被表示为一个数组。这使得<>变得相当缓慢,因为需要分配一个新的数组,并将每个Text复制到其中。您可以通过先将每个片段转换为String,然后将它们连接起来来解决此问题。我想Text可能也提供了一种有效的同时连接多个文本的方法(正如评论者所提到的,您可以使用lazy builder),但是对于此目的,它会更慢。另一个很好的选择可能是Text的lazy版本,它可能支持高效的连接。

共享

在基于String的实现中,description字段根本不需要复制。它只是在Location和显示该Location的结果之间共享。在Text版本中无法实现这一点。


3

在字符串操作中,您没有完全评估所有的字符串操作 - (++) 和 replicate。

如果您将基准测试更改为:

benchmarks = [ bench "show" (whnf (length.show) l) ]

您会发现字符串操作大约需要520纳秒,大约比其他操作慢10倍。


我做了测试,发现字符串版本的运行时间是700ns,而文本版本的则需要2600ns。问题显然出在show方法的实现上,而不在评估过程中——虽然调用length方法有助于确保所有内容都被完全评估。 - Feenaboccles

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接