亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

處理巨大的文本文件時突然內存消耗跳躍導致內存不足異常

處理巨大的文本文件時突然內存消耗跳躍導致內存不足異常

C#
青春有我 2021-11-14 17:25:30
我需要處理一個非常大的文本文件(6-8 GB)。我寫了下面附上的代碼。不幸的是,每次輸出文件達到(在源文件旁邊創建)達到~2GB 時,我觀察到內存消耗突然增加(~100MB 到幾 GB)和結果 -內存不足異常。調試器指示 OOM 發生在while ((tempLine = streamReader.ReadLine()) != null) 我僅針對 .NET 4.7 和 x64 架構。單行最多 50 個字符長。我可以解決這個問題并將原始文件拆分為較小的部分,以免在處理時遇到問題并將結果合并回一個文件,但我不想這樣做。代碼:public async Task PerformDecodeAsync(string sourcePath, string targetPath)    {        var allLines = CountLines(sourcePath);        long processedlines = default;        using (File.Create(targetPath));        var streamWriter = File.AppendText(targetPath);        var decoderBlockingCollection = new BlockingCollection<string>(1000);        var writerBlockingCollection = new BlockingCollection<string>(1000);        var producer = Task.Factory.StartNew(() =>        {            using (var streamReader = new StreamReader(File.OpenRead(sourcePath), Encoding.Default, true))            {                string tempLine;                while ((tempLine = streamReader.ReadLine()) != null)                {                    decoderBlockingCollection.Add(tempLine);                }                decoderBlockingCollection.CompleteAdding();            }        });        var consumer1 = Task.Factory.StartNew(() =>        {            foreach (var line in decoderBlockingCollection.GetConsumingEnumerable())            {                short decodeCounter = 0;                StringBuilder builder = new StringBuilder();                foreach (var singleChar in line)                {                    var positionInDecodeKey = decodingKeysList[decodeCounter].IndexOf(singleChar);                    if (positionInDecodeKey > 0)                        builder.Append(model.Substring(positionInDecodeKey, 1));                    else                        builder.Append(singleChar);                    if (decodeCounter > 18)                        decodeCounter = 0;                    else ++decodeCounter;                }            }        });非常感謝解決方案以及如何對其進行更多優化的建議。
查看完整描述

2 回答

?
慕村225694

TA貢獻1880條經驗 獲得超4個贊

就像我說的,我可能會先做一些更簡單的事情,除非或直到證明它表現不佳。正如 Adi 在他們的回答中所說,這項工作似乎受 I/O 限制 - 因此為其創建多個任務似乎沒有什么好處。


publiv void PerformDecode(string sourcePath, string targetPath)

{

    File.WriteAllLines(targetPath,File.ReadLines(sourcePath).Select(line=>{

        short decodeCounter = 0;

        StringBuilder builder = new StringBuilder();

        foreach (var singleChar in line)

        {

            var positionInDecodeKey = decodingKeysList[decodeCounter].IndexOf(singleChar);

            if (positionInDecodeKey > 0)

                builder.Append(model.Substring(positionInDecodeKey, 1));

            else

                builder.Append(singleChar);


            if (decodeCounter > 18)

                decodeCounter = 0;

            else ++decodeCounter;

        }

        return builder.ToString();

    }));

}

現在,當然,這段代碼在完成之前實際上是阻塞的,這就是我沒有標記它的原因async。但是,你的也是如此,它應該已經警告過這一點。


(您可以嘗試對Select部分使用 PLINQ 而不是 LINQ,但老實說,我們在這里所做的處理量看起來微不足道;在應用任何此類更改之前先進行分析)


查看完整回答
反對 回復 2021-11-14
?
qq_笑_17

TA貢獻1818條經驗 獲得超7個贊

由于您所做的工作主要是 IO 綁定,因此您并沒有真正從并行化中獲得任何好處。在我看來(如果我錯了,請糾正我)您的轉換算法不依賴于您逐行閱讀文件,因此我建議改為執行以下操作:


void Main()

{

    //Setup streams for testing

    using(var inputStream = new MemoryStream())

    using(var outputStream = new MemoryStream())

    using (var inputWriter = new StreamWriter(inputStream))

    using (var outputReader = new StreamReader(outputStream))

    {

        //Write test string and rewind stream

        inputWriter.Write("abcdefghijklmnop");

        inputWriter.Flush();

        inputStream.Seek(0, SeekOrigin.Begin);


        var inputBuffer = new byte[5];

        var outputBuffer = new byte[5];

        int inputLength;

        while ((inputLength = inputStream.Read(inputBuffer, 0, inputBuffer.Length)) > 0)

        {

            for (var i = 0; i < inputLength; i++)

            {

                //transform each character

                outputBuffer[i] = ++inputBuffer[i];

            }


            //Write to output

            outputStream.Write(outputBuffer, 0, inputLength);

        }


        //Read for testing

        outputStream.Seek(0, SeekOrigin.Begin);

        var output = outputReader.ReadToEnd();

        Console.WriteLine(output);


        //Outputs: "bcdefghijklmnopq"

    }


}

顯然,您將使用 FileStreams 而不是 MemoryStreams,并且您可以將緩沖區長度增加到更大的值(因為這只是一個演示示例)。此外,由于您的原始方法是 Async,因此您可以使用 Stream.Write 和 Stream.Read 的異步變體



查看完整回答
反對 回復 2021-11-14
  • 2 回答
  • 0 關注
  • 242 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號