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

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

使用 C# 讀取數百萬個小文件

使用 C# 讀取數百萬個小文件

PHP
寶慕林4294392 2024-01-20 21:03:41
我有數百萬個每天生成的日志文件,我需要讀取所有這些文件并將其放在一起作為單個文件,以便在其他應用程序中對其進行一些處理。我正在尋找最快的方法來做到這一點。目前我正在使用線程、任務和并行,如下所示:Parallel.For(0, files.Length, new ParallelOptions { MaxDegreeOfParallelism = 100 }, i =>{    ReadFiles(files[i]);});void ReadFiles(string file){    try    {        var txt = File.ReadAllText(file);        filesTxt.Add(tmp);    }    catch { }    GlobalCls.ThreadNo--;}或者foreach (var file in files){    //Int64 index = i;    //var file = files[index];    while (Process.GetCurrentProcess().Threads.Count > 100)    {         Thread.Sleep(100);        Application.DoEvents();    }    new Thread(() => ReadFiles(file)).Start();    GlobalCls.ThreadNo++;    // Task.Run(() => ReadFiles(file));      }問題是,讀取幾千個文件后,讀取速度越來越慢!知道為什么嗎?讀取數百萬個小文件的最快方法是什么?謝謝。
查看完整描述

3 回答

?
呼如林

TA貢獻1798條經驗 獲得超3個贊

看起來您正在將所有文件的內容加載到內存中,然后再將它們寫回單個文件。這可以解釋為什么這個過程隨著時間的推移變得更慢。

優化該過程的一種方法是將讀取部分與寫入部分分開,并并行進行。這稱為生產者-消費者模式。Parallel它可以使用類、線程或任務來實現,但我將演示基于強大的TPL 數據流庫的實現,該庫特別適合此類作業。

private static async Task MergeFiles(IEnumerable<string> sourceFilePaths,

? ? string targetFilePath, CancellationToken cancellationToken = default,

? ? IProgress<int> progress = null)

{

? ? var readerBlock = new TransformBlock<string, string>(async filePath =>

? ? {

? ? ? ? return File.ReadAllText(filePath); // Read the small file

? ? }, new ExecutionDataflowBlockOptions()

? ? {

? ? ? ? MaxDegreeOfParallelism = 2, // Reading is parallelizable

? ? ? ? BoundedCapacity = 100, // No more than 100 file-paths buffered

? ? ? ? CancellationToken = cancellationToken, // Cancel at any time

? ? });


? ? StreamWriter streamWriter = null;


? ? int filesProcessed = 0;

? ? var writerBlock = new ActionBlock<string>(text =>

? ? {

? ? ? ? streamWriter.Write(text); // Append to the target file

? ? ? ? filesProcessed++;

? ? ? ? if (filesProcessed % 10 == 0) progress?.Report(filesProcessed);

? ? }, new ExecutionDataflowBlockOptions()

? ? {

? ? ? ? MaxDegreeOfParallelism = 1, // We can't parallelize the writer

? ? ? ? BoundedCapacity = 100, // No more than 100 file-contents buffered

? ? ? ? CancellationToken = cancellationToken, // Cancel at any time

? ? });


? ? readerBlock.LinkTo(writerBlock,

? ? ? ? new DataflowLinkOptions() { PropagateCompletion = true });


? ? // This is a tricky part. We use BoundedCapacity, so we must propagate manually

? ? // a possible failure of the writer to the reader, otherwise a deadlock may occur.

? ? PropagateFailure(writerBlock, readerBlock);


? ? // Open the output stream

? ? using (streamWriter = new StreamWriter(targetFilePath))

? ? {

? ? ? ? // Feed the reader with the file paths

? ? ? ? foreach (var filePath in sourceFilePaths)

? ? ? ? {

? ? ? ? ? ? var accepted = await readerBlock.SendAsync(filePath,

? ? ? ? ? ? ? ? cancellationToken); // Cancel at any time

? ? ? ? ? ? if (!accepted) break; // This will happen if the reader fails

? ? ? ? }

? ? ? ? readerBlock.Complete();

? ? ? ? await writerBlock.Completion;

? ? }


? ? async void PropagateFailure(IDataflowBlock block1, IDataflowBlock block2)

? ? {

? ? ? ? try { await block1.Completion.ConfigureAwait(false); }

? ? ? ? catch (Exception ex)

? ? ? ? {

? ? ? ? ? ? if (block1.Completion.IsCanceled) return; // On cancellation do nothing

? ? ? ? ? ? block2.Fault(ex);

? ? ? ? }

? ? }

}

使用示例:


var cts = new CancellationTokenSource();

var progress = new Progress<int>(value =>

{

? ? // Safe to update the UI

? ? Console.WriteLine($"Files processed: {value:#,0}");

});

var sourceFilePaths = Directory.EnumerateFiles(@"C:\SourceFolder", "*.log",

? ? SearchOption.AllDirectories); // Include subdirectories

await MergeFiles(sourceFilePaths, @"C:\AllLogs.log", cts.Token, progress);

BoundedCapacity用于控制內存使用。

如果磁盤驅動器是SSD,您可以嘗試使用MaxDegreeOfParallelism大于2的值讀取。

為了獲得最佳性能,您可以考慮寫入與包含源文件的驅動器不同的磁盤驅動器。

TPL 數據流庫可作為.NET Framework 的包提供,并且內置于 .NET Core。


查看完整回答
反對 回復 2024-01-20
?
智慧大石

TA貢獻1946條經驗 獲得超3個贊

當涉及到IO操作時,CPU并行是沒有用的。您的 IO 設備(磁盤、網絡等)是您的瓶頸。同時從設備讀取數據可能會降低性能。



查看完整回答
反對 回復 2024-01-20
?
MYYA

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

也許您可以只使用 PowerShell 來連接文件,

另一種替代方法是編寫一個程序,使用FileSystemWatcher類來監視新文件并在創建時追加它們。


查看完整回答
反對 回復 2024-01-20
  • 3 回答
  • 0 關注
  • 304 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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