🎃
C#で巨大なファイルを操作する時の知見
ファイルの書き込み・読み込みは遅い。
なので、メモリに余裕があるなら直接ファイルに読み書きするより、一旦メモリに引き上げて処理したほうが早い。
書き込みは一旦MemoryStream
とかに書いてからCopyToAsync
でまとめて書き込むのが早い。
File.WriteAllLinesAsync
はかなり遅かった。多分内部で1行書くごとにawaitしてそうな気がする(確認はしてない)。
読込は File.ReadLines()
がいいかも。
以下はCSVを加工するサンプル。Ryzen 5800Xで6.5万行を加工するのに3秒くらい。
// 読込はReadLinesで1行ずつ
var lines = File.ReadLines(inputFile);
// 各行を加工(遅延実行)
var result = lines
.AsParallel().WithDegreeOfParallelism(Environment.ProcessorCount)
.Select(ProcessLine);
// 書き出しはファイルにではなく、一旦メモリに書き込み
// 1行ずつ書きたいので、StreamWriterを使う
using var memoryStream = new MemoryStream();
using var memoryWriter = new StreamWriter(memoryStream, Encoding.UTF8);
foreach (var line in result)
{
await memoryWriter.WriteLineAsync(line);
}
// 書き出しは一気にMemoryStreamからコピーしてしまう
// await File.WriteAllLines(result); で 30秒かかってたのが1秒未満になった
using var fileWriter = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);
await memoryStream.CopyToAsync(fileWriter);
一番遅いのはファイル読み込みなので、もっと早くできるかも?
一旦 List<string>
に引き上げたけど、Listの生成自体に時間がかかっててたので辞めた(0.5秒かかってた)。
Discussion