如何用恒定的内存处理两条长行?

杨哲旺

输入文件由两行组成,每行包含许多数字

1 2 3 4... 
5 6 7 8... 

我想处理每一行的数据,如下所示:

doSomething :: [Int] -> [Int] -> Int
doSomething [] y = 0 -- stop execution. I'm concerted in memory behavior only.
doSomething (x:xs) y = doSomething xs y
main = do
    inputdata <- getContents
    let (x:xs) = lines inputdata
        firstLine = map (read ::String->Int) $ words $ x
        secondLine = map (read ::String->Int) $ words $ head xs
    print $ doSomething firstLine secondLine

当我运行该程序时,堆分析显示如下:

如果我不使用secondLine(xs),则该程序将以恒定内存运行。列表的每个条目都firstLine经过处理,然后由GC丢弃。

  1. 为什么消耗的内存这么大?我看到分配的内存量约为100MB,但实际输入数据大小为5MB。

  2. 是否head xs强制将整个第一行读入内存,甚至secondLine根本不使用?这是堆概要分析图内存增加的主要原因吗?

  3. 如何处理具有恒定内存的两行,如后面的执行图?

  4. 如果3)的答案取决于处理顺序,我该如何先处理第二行,然后处理第一行?

Zakyggaps

Q1)为什么占用的内存这么大?我看到分配的内存量约为100MB,但实际输入数据大小为5MB。

String在Haskell中,它是的类型别名[Char],因此沿着实际字节,编译器还必须保留构造函数,内存中每个字符的指向装箱字符的指针和指向下一个构造函数的指针,导致内存使用率> 10倍而不是C样式的字符串。更糟糕的是,文本会在内存中多次存储。

Q3)如何处理具有恒定内存的两行,就像后面的执行图一样?
Q4)如果对Q3)的答案取决于处理顺序,我该如何先处理第二行,然后处理第一行?

不,您不能先处理第二行,因为该lines函数必须评估第一行中的每个字节才能命中'\ n'换行符。

Q2)头xs是否会强制将整个第一行读入内存,甚至根本不使用secondLine?这是堆概要分析图内存增加的主要原因吗?

并不是head防止第一行被GC。如果您调整其类型签名doSomethingxs直接传递给它,则仍然会发生空间泄漏关键是(未优化)编译器secondLinedoSomething最终到达第一个模式之前不会知道没有使用过,因此程序会保留对的引用xs顺便说一句,如果使用-O2编译,则程序将以恒定内存运行。

导致程序空间泄漏的原因主要是以下行:

let (x:xs) = lines inputdata

x或被xs丢弃时,此let子句将内联在转储的Core中。仅当稍后两者都被引用时,Core才会表现出奇怪的行为:它构造一个元组,通过模式匹配对其进行销毁,然后将这两个部分再次构造为一个元组,因此secondLine实际上通过保留对程序的引用就保留了对元组的引用(x, xs)因此第一行将永远不会被GC。

核心已secondLine注释掉:

Rec {
doSomething_rjH
doSomething_rjH =
  \ ds_d1lv y_alG ->
    case ds_d1lv of _ {
      [] -> I# 0;
      : x_alH xs_alI -> doSomething_rjH xs_alI y_alG
    }
end Rec }

main
main =
  >>=
    $fMonadIO
    getContents
    (\ inputdata_app ->
       print
         $fShowInt
         (doSomething_rjH
            (map
               (read $fReadInt)
               (words
                  (case lines inputdata_app of _ {
                     [] -> case irrefutPatError "a.hs:6:9-32|(x : xs)"# of wild1_00 { };
                     : x_auf xs_aug -> x_auf
                   })))
            ([])))

main
main = runMainIO main

有空间泄漏的核心:

Rec {
doSomething_rjH
doSomething_rjH =
  \ ds_d1ol y_alG ->
    case ds_d1ol of _ {
      [] -> I# 0;
      : x_alH xs_alI -> doSomething_rjH xs_alI y_alG
    }
end Rec }

main
main =
  >>=
    $fMonadIO
    getContents
    (\ inputdata_app ->
       -- *** Construct ***
       let {
         ds_d1op
         ds_d1op =
           case lines inputdata_app of _ {
             [] -> irrefutPatError "a.hs:6:9-30|x : xs"#;
             : x_awM xs_awN -> (x_awM, xs_awN)
           } } in
       -- *** Destruct ***
       let {
         xs_awN
         xs_awN = case ds_d1op of _ { (x_awM, xs1_XwZ) -> xs1_XwZ } } in
       let {
         x_awM
         x_awM = case ds_d1op of _ { (x1_XwZ, xs1_XwU) -> x1_XwZ } } in
       -- *** Construct ***
       let {
         ds1_d1oq
         ds1_d1oq = (x_awM, xs_awN) } in
       print
         $fShowInt
         -- *** Destruct ***
         (doSomething_rjH
            (map
               (read $fReadInt)
               (words (case ds1_d1oq of _ { (x1_Xx1, xs1_Xx3) -> x1_Xx1 })))
            (map
               (read $fReadInt)
               (words
                  (head (case ds1_d1oq of _ { (x1_Xx1, xs1_Xx3) -> xs1_Xx3 }))))))

main
main = runMainIO main

let子句替换case .. of子句将修复空间泄漏:

doSomething :: [Int] -> [Int] -> Int
doSomething [] _ = 0 -- stop execution. I'm concerted in memory behavior only.
doSomething (_:xs) y = doSomething xs y

main :: IO ()
main = do
  inputdata <- getContents
  case lines inputdata of
    x:xs -> do
      let
        firstLine = map (read ::String->Int) $ words x
        secondLine = map (read ::String->Int) $ words $ head xs
      print $ doSomething firstLine secondLine

转储的核心。这次没有发生“先构建然后销毁”的模式:

Rec {
doSomething_rjG
doSomething_rjG =
  \ ds_d1o6 ds1_d1o7 ->
    case ds_d1o6 of _ {
      [] -> I# 0;
      : ds2_d1o8 xs_alG -> doSomething_rjG xs_alG ds1_d1o7
    }
end Rec }

main
main =
  >>=
    $fMonadIO
    getContents
    (\ inputdata_apn ->
       case lines inputdata_apn of _ {
         [] -> patError "a.hs:(8,3)-(13,46)|case"#;
         : x_asI xs_asJ ->
           print
             $fShowInt
             (doSomething_rjG
                (map (read $fReadInt) (words x_asI))
                (map (read $fReadInt) (words (head xs_asJ))))
       })

main
main = runMainIO main

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在两条特定行之间提取数据

来自分类Dev

如何用两条闭合线正确填充一个 SVG 路径?

来自分类Dev

处理两条标记线之间的文本文件行

来自分类Dev

处理两条标记线之间的文本文件行

来自分类Dev

如何比较两条路径

来自分类Dev

如何保持两条主线?

来自分类Dev

如何合并两条路径?

来自分类Dev

如何从两个不同的文件中打印两条匹配的行?

来自分类Dev

如何用齐奥效应和不同类型的环境组成两条Http4s路由

来自分类Dev

如何在两条不同颜色的行中绘制 xlabel?

来自分类Dev

如何合并以这两行的单词总和为条件的两条相邻行(递归)

来自分类Dev

在vim中删除两条非连续行的方法

来自分类Dev

使用awk更改两条不同的行中的值

来自分类Dev

两条相同的反应状态行返回不同的结果

来自分类Dev

在文件顶部添加两条注释行

来自分类Dev

如何找出C中两条共面线的交点

来自分类Dev

如何使用GGPlot绘制两条虚线虚线

来自分类Dev

如何填充ggplot图中两条曲线之间的间隙

来自分类Dev

如何:“ postMessage”可以发送两条消息吗?

来自分类Dev

Microsoft Excel:如何找到两条线的交点?

来自分类Dev

如何在单个路由中聚合两条消息?

来自分类Dev

连接两条折线

来自分类Dev

表示JS堆栈,创建一个处理两条不同路径的工厂

来自分类Dev

在Matplotlib中同时对同一图中的两条曲线进行动画处理

来自分类Dev

Camel 中的两条路由是否引用了相同的处理 bean 并行执行?

来自分类Dev

SQL Server - 在两条不同的行上显示两个不同的日期

来自分类Dev

在Java文件中使用sed命令替换两条注释行之间的行

来自分类Dev

我在两条不同的行而不是一行中得到我的输出结果

来自分类Dev

MongoDB两条相同的记录

Related 相关文章

  1. 1

    如何在两条特定行之间提取数据

  2. 2

    如何用两条闭合线正确填充一个 SVG 路径?

  3. 3

    处理两条标记线之间的文本文件行

  4. 4

    处理两条标记线之间的文本文件行

  5. 5

    如何比较两条路径

  6. 6

    如何保持两条主线?

  7. 7

    如何合并两条路径?

  8. 8

    如何从两个不同的文件中打印两条匹配的行?

  9. 9

    如何用齐奥效应和不同类型的环境组成两条Http4s路由

  10. 10

    如何在两条不同颜色的行中绘制 xlabel?

  11. 11

    如何合并以这两行的单词总和为条件的两条相邻行(递归)

  12. 12

    在vim中删除两条非连续行的方法

  13. 13

    使用awk更改两条不同的行中的值

  14. 14

    两条相同的反应状态行返回不同的结果

  15. 15

    在文件顶部添加两条注释行

  16. 16

    如何找出C中两条共面线的交点

  17. 17

    如何使用GGPlot绘制两条虚线虚线

  18. 18

    如何填充ggplot图中两条曲线之间的间隙

  19. 19

    如何:“ postMessage”可以发送两条消息吗?

  20. 20

    Microsoft Excel:如何找到两条线的交点?

  21. 21

    如何在单个路由中聚合两条消息?

  22. 22

    连接两条折线

  23. 23

    表示JS堆栈,创建一个处理两条不同路径的工厂

  24. 24

    在Matplotlib中同时对同一图中的两条曲线进行动画处理

  25. 25

    Camel 中的两条路由是否引用了相同的处理 bean 并行执行?

  26. 26

    SQL Server - 在两条不同的行上显示两个不同的日期

  27. 27

    在Java文件中使用sed命令替换两条注释行之间的行

  28. 28

    我在两条不同的行而不是一行中得到我的输出结果

  29. 29

    MongoDB两条相同的记录

热门标签

归档