1

これは、1MIntの数字を作成してリストに入れるコードです。

main = do
  let l =  [1..1000000]
  putStrLn $ show $ sum (foldl (\aux p -> p:aux) [] l)

(私はそれがより最適かもしれないことを知っています (sumfold) しかし、私のポイントは異なります.) そして、このバージョンを見てください.

import qualified Data.ByteString.Lazy.Char8 as B
import qualified Data.ByteString.Lazy.Builder as Builder
import Data.ByteString.Lazy.Builder.ASCII
import Data.Maybe
import Data.List

main = do
    let l = map (Builder.toLazyByteString . intDec ) [1..1000000]
    let l2 = map (fst . fromJust . B.readInt) l
    putStrLn $ show $ sum (foldl' (\aux p -> p:aux) [] l2)

このバージョンには 90MB のメモリが必要です。なんで?ここにプロファイリング出力があります

1M ByteString を作成するためのメモリ消費量

紫のエリアは?

コメントを読んだ後に編集 して、明確化を追加したいと思います。

これはテストです。メモリに 1M の数値を保持したい (ルックアップ テーブルを作成しています)。だから私は「リスト全体を強制的にメモリに保持したい」のです。しかし、バイト文字列を保持したくありません。私の小さなコードは、ディスクからバイト文字列をロードし、それを整数に変換し、整数をメモリに保持する場合のシミュレーションです。(それが私の目標です)。しかし、どういうわけかバイト文字列がメモリに残ります。なんで?

4

2 に答える 2

2

問題はここでの怠惰です。

main = do
    let l = map (Builder.toLazyByteString . intDec ) [1..1000000]
    let l2 = map (fst . fromJust . B.readInt) l
    putStrLn $ show $ sum (foldl' (\aux p -> p:aux) [] l2)

サンクを強制的に評価するByteStringまで sを保持します。その前に、それぞれが 1 つの short への参照を持つサンクのリストがあります。逆にすると、サンク + s のリスト全体が一度にメモリに強制されます。sumfst . fromJust . B.readIntByteStringByteString

sを保持したくない場合はByteString、サンクを強制的に評価します。

main = do
    let l = map (Builder.toLazyByteString . intDec ) [1..1000000]
    let l2 = map (fst . fromJust . B.readInt) l
    putStrLn $ show $ sum (foldl' (\aux p -> p `seq` (p:aux)) [] l2)

Ints の単純なリスト以上のものを必要とせず、はるかに少ないメモリ使用量を生成します。

ここに画像の説明を入力

于 2013-08-21T21:11:04.427 に答える