所以我有一个位置类
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
使用标准,我对show
和String
实施中Data.Text
所花费的时间进行了基准测试:
benchmarks = [ bench "show" (whnf show l) ]
where l = Location {
title="My Title"
, description = "This is the description."
}
String
实施需要34ns,Data.Text
实施几乎六倍,为170ns
如何让Data.Text
的工作速度与String
一样快?
编辑:愚蠢的错误
我不确定这是怎么发生的,但是我不能复制原来的速度差异:现在对于String和Text我分别得到28ns和24ns
对于更具侵略性的bench "length.show" (whnf (length . show) l)
基准测试,对于字符串和文本,我分别得到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
将构建器转换为String将转义换行符。如果我将其替换为LT.unpack $ Bldr.toLazyText
,其中LT
是Data.Text.Lazy
的合格导入,则我获得192ns。
我在Mac笔记本电脑上对此进行了测试,我怀疑我的时间因机器噪音而受到严重破坏。感谢您的指导。
答案 0 :(得分:3)
你不能让它快速,但你可以加速它。
Text
表示为数组。这使得<>
相当慢,因为必须分配新数组并将每个Text
复制到其中。您可以先将每个部分转换为String
,然后再连接它们来解决此问题。我想Text
可能也提供了一种有效的方法来同时连接多个文本(作为commenter提及,你可以使用一个懒惰的构建器),但为了这个目的,这将更慢。另一个好的选择可能是Text
的惰性版本,它可能支持有效的连接。
在基于String
的实施中,根本不需要复制description
字段。它仅在Location
和显示Location
的结果之间共享。使用Text
版本无法实现此目的。
答案 1 :(得分:3)
在String情况下,您没有完全评估所有字符串操作 - (++)和复制。
如果您将基准更改为:
benchmarks = [ bench "show" (whnf (length.show) l) ]
你会发现String情况需要大约520 ns - 大约10倍。