На первый взгляд выбранный вами подход выглядит нормально - он должен работать нормально, и нет ничего очевидного, что может вызвать, например, много мусора.
Главное, что я думаю, это то, что вы будете толькоиспользовать одно из этих шестнадцати ядер: нечего делить нагрузку между остальными пятнадцатью.
I думаю самый простой способ сделать это - разделить большой 20-гигабайтный файл на шестнадцатькуски, затем проанализируйте каждый из кусков вместе, затем снова объедините куски вместе.Дополнительное время, необходимое для разделения и повторной сборки файла, должно быть минимальным по сравнению с ~ 16-кратным выигрышем при сканировании этих шестнадцати блоков вместе.
В общих чертах, один из способов сделать это может быть:
private List<string> SplitFileIntoChunks(string baseFile)
{
// Split the file into chunks, and return a list of the filenames.
}
private void AnalyseChunk(string filename)
{
// Analyses the file and performs replacements,
// perhaps writing to the same filename with a different
// file extension
}
private void CreateOutputFileFromChunks(string outputFile, List<string> splitFileNames)
{
// Combines the rewritten chunks created by AnalyseChunk back into
// one large file, outputFile.
}
public void AnalyseFile(string inputFile, string outputFile)
{
List<string> splitFileNames = SplitFileIntoChunks(inputFile);
var tasks = new List<Task>();
foreach (string chunkName in splitFileNames)
{
var task = Task.Factory.StartNew(() => AnalyseChunk(chunkName));
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
CreateOutputFileFromChunks(outputFile, splitFileNames);
}
Одна крошечная гнида: перенесите расчет длины потока из цикла, вам нужно получить его только один раз.
РЕДАКТИРОВАТЬ: также включите идею @Pavel Gatilov, чтобы инвертировать логикувнутренний цикл и поиск каждого слова в строке в списке 12 миллионов.