Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance 提高基于文本的XML渲染器的生产效率和性能_Performance_Haskell - Fatal编程技术网

Performance 提高基于文本的XML渲染器的生产效率和性能

Performance 提高基于文本的XML渲染器的生产效率和性能,performance,haskell,Performance,Haskell,我正在尝试为XML.Light数据类型编写一个高效的XML呈现,我正在尝试使用data.Text.Lazy.Builder来实现这一点,因为这似乎是一个显而易见的选择。但是,我很难从我的解决方案中获得任何性能: {-# LANGUAGE OverloadedStrings #-} import Data.Text (Text, unpack) import Text.XML.Light import qualified Data.Text.Lazy as LT import qualified

我正在尝试为XML.Light数据类型编写一个高效的XML呈现,我正在尝试使用
data.Text.Lazy.Builder
来实现这一点,因为这似乎是一个显而易见的选择。但是,我很难从我的解决方案中获得任何性能:

{-# LANGUAGE OverloadedStrings #-}
import Data.Text (Text, unpack)
import Text.XML.Light
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Builder as LB

import Data.Foldable (foldMap)
import Data.Monoid (mconcat)

data Tag = Tag !Text

data Artist = Artist { artistName :: !Text , artistTags :: ![Tag] }

class ToXML a where toXML :: a -> Content

instance ToXML Artist where
  toXML a = Elem $
    Element (unqual "artist") []
      [ text (artistName a)
      , Elem $ Element (unqual "tag-list") []
          (map toXML (artistTags a))
          Nothing
      ]
      Nothing

instance ToXML Tag where
  toXML (Tag t) = Elem $ Element (unqual "tag") [] [ text t ] Nothing

text :: Text -> Content
text t = Text $ CData CDataText (unpack t) Nothing

render :: Content -> LB.Builder
render (Elem e) = renderElement e
render (Text s) = LB.fromString (cdData s)

renderElement :: Element -> LB.Builder
renderElement element = mconcat
  [ LB.singleton '<'
  , LB.fromString . qName . elName $ element
  , LB.singleton '>'
  , foldMap render (elContent element)
  , LB.fromText "</"
  , LB.fromString . qName .elName $ element
  , LB.singleton '>'
  ]

main :: IO ()
main = let artist = Artist "Nirvana" (replicate 5000000 (Tag "Hi"))
           xml = Element (unqual "metadata") [] [ toXML artist ] Nothing
       in print (LT.length . LB.toLazyText . renderElement $ xml)
这太可怕了。不仅是最低的生产率,堆中还分配了超过7GiB的内存来呈现64MB的XML。这看起来效率太低了!然而,我不知道这些垃圾到底是从哪里来的。我用
+RTS-p
生成了一个堆配置文件,并用
hp2ps
呈现它:

我还用
+RTS-l
运行了它,并用ThreadScope渲染了它:

遗憾的是,我现在不知道该怎么做,就是把这些部分放在一起,提高生产率,降低内存使用率。我确实想知道
XML.Light
中的类型是否不是最佳的(没有严格性,
String
超过
Text
),但仍然如此缓慢


我还观察到一些我觉得有点奇怪的事情。如果我将
main
更改为:

main :: IO ()
main = let artist = Artist "Nirvana" (replicate 5000000 (Tag "Hi"))
           xml = Element (unqual "metadata") [] [ toXML artist ] Nothing
       in print (LT.length $ LB.toLazyText $ mconcat $ map (render.toXML) $ artistTags artist)

生产率高达94%,因此可能是由于在
toXML
中递归有问题,而且过于懒惰。

我解决了这个问题,我认为这是GHC中的一个缺陷

如果我们改变这一行:

, LB.fromString . qName . elName $ element
为此:

, LB.fromString $ qName . elName $ element
然后我们得到了我们期望的表现。似乎用
qName
组合
LB.fromString
可以防止一些内联,因此不会发生融合。我认为这真的很危险,所以我将把这个问题转移到GHCs bug tracker的bug报告中,看看那边的智者是怎么想的


说一句“抓住你了!”

你知道
artistTags::![Tag]
不太重要,是吗?只需查看列表是否为空即可。您可以尝试在
Artist
实例(deepseq或其他)中强制执行
(map-toXML(artistTags a))
。这可能会有帮助也可能会有伤害,现在还不知道
foldMap render(elContent元素)
也可以有一部分,但是一般来说,
text
是非常有效的,所以我不把它列为主要怀疑因素。
, LB.fromString $ qName . elName $ element