Как выполнить асинхронное чтение файлов в C # 2.0?
-
03-07-2019 - |
Вопрос
У меня есть приложение, которому необходимо перебирать все строки в текстовых файлах размером более гигабайта.Некоторые из этих файлов содержат 10 или 100 миллионов строк.
Пример моего текущего (и синхронного) чтения выглядит примерно так...
using (FileStream stream = new FileStream(args[0], FileMode.Open, FileAccess.Read, FileShare.Read)) {
using (StreamReader streamReader = new StreamReader(stream)) {
string line;
while (!string.IsNullOrEmpty(line = streamReader.ReadLine())) {
//do stuff with the line string...
}
}
}
Я прочитал кое-что о методах потоковой передачи асинхронного ввода-вывода .Net, и мне нужна некоторая помощь по двум конкретным вопросам, касающимся этой проблемы.
Во-первых, получу ли я повышение производительности за счет асинхронного чтения этих файлов, если мне нужна полная информация о каждой строке, которая обычно короткая, но разной длины (между каждой из строк в файле нет взаимосвязи)?
Во-вторых, как мне преобразовать приведенный выше код в асинхронное чтение, чтобы я мог обрабатывать каждую строку построчно, как я делаю сейчас?
Решение
Вместо того, чтобы делать чтение строки асинхронным, вы могли бы попробовать сделать чтение файла асинхронным.Это включает в себя весь код в вашем вопросе в одном рабочем делегате.
static void Main(string[] args)
{
WorkerDelegate worker = new WorkerDelegate(Worker);
// Used for thread and result management.
List<IAsyncResult> results = new List<IAsyncResult>();
List<WaitHandle> waitHandles = new List<WaitHandle>();
foreach (string file in Directory.GetFiles(args[0], "*.txt"))
{
// Start a new thread.
IAsyncResult res = worker.BeginInvoke(file, null, null);
// Store the IAsyncResult for that thread.
results.Add(res);
// Store the wait handle.
waitHandles.Add(res.AsyncWaitHandle);
}
// Wait for all the threads to complete.
WaitHandle.WaitAll(waitHandles.ToArray(), -1, false); // for < .Net 2.0 SP1 Compatibility
// Gather all the results.
foreach (IAsyncResult res in results)
{
try
{
worker.EndInvoke(res);
// object result = worker.EndInvoke(res); // For a worker with a result.
}
catch (Exception ex)
{
// Something happened in the thread.
}
}
}
delegate void WorkerDelegate(string fileName);
static void Worker(string fileName)
{
// Your code.
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (StreamReader streamReader = new StreamReader(stream))
{
string line;
while (!string.IsNullOrEmpty(line = streamReader.ReadLine()))
{
//do stuff with the line string...
}
}
}
}
Другие советы
Асинхронный шаблон называется BeginRead()/EndRead() .
Получите вы повышение или нет, во многом зависит от того, что еще происходит во время чтения.Есть ли что-то еще, что ваше приложение может делать во время ожидания результатов чтения?Если нет, то переход на асинхронный режим не сильно поможет...
Асинхронное чтение просто приведет к тому, что head будет искать больше для каждого блока.Вы получите больший прирост производительности за счет хорошей дефрагментации файлов в файловой системе и использования синхронного чтения.
Как уже указывалось, передача строчной обработки другим потокам должна дать толчок (особенно на многоядерных процессорах).
Если производительность сверхкритична, я бы рекомендовал изучить взаимодействие для FILE_FLAG_SEQUENTIAL_SCAN
Видишь подробности здесь
Еще лучше написать крошечное приложение на C ++, которое просматривает файл с этим флагом, чтобы увидеть, повышает ли это производительность.