Прежде всего, не ясно, что два потока обязательно будут здесь полезны.Один поток, считывающий по одной строке за раз (что довольно просто при StreamReader
) и обрабатывающий каждую строку по ходу, может работать как минимум так же хорошо.Чтения файлов буферизуются, и ОС может читать перед вашим кодом, запрашивая данные, и в этом случае большинство ваших операций чтения либо завершатся немедленно, потому что ОС уже прочитала следующую строку с диска, либо обе ваши темыприходится ждать, потому что данных на диске нет.(И если два потока сидят в ожидании диска, это не приводит к тому, что все происходит быстрее, чем ожидание одного потока.) Единственное возможное преимущество состоит в том, что вы избегаете мертвого времени, выполняя следующее чтение до того, как закончите обработку предыдущего,но операционная система часто делает это за вас в любом случае.Таким образом, преимущества многопоточности здесь будут в лучшем случае незначительными.
Однако, поскольку вы говорите, что делаете это как учебное упражнение, это не может быть проблемой ...
I 'Использовать BlockingCollection<string>
в качестве механизма передачи данных из одного потока в другой.(Пока вы используете .NET 4 или более позднюю версию. А если нет ... Я предлагаю вам перейти на .NET 4 - это значительно упростит эту задачу.) Вы прочтете строку из файла и поместите ее вколлекция из одного потока:
string nextLine = myFileReader.ReadLine();
myBlockingCollection.Add(nextLine);
А затем какой-то другой поток может извлечь строки из этого:
while (true)
{
string lineToProcess = myBlockingCollection.Take();
ProcessLine(lineToProcess);
}
Это позволит потоку чтения проходить через файл так же быстро, как идиск позволит это сделать, в то время как поток обработки обрабатывает данные с любой возможной скоростью.Take
Метод просто сидит и ждет, если ваш поток обработки опережает поток чтения файла.
Одна из проблем заключается в том, что ваш поток чтения может продвинуться далеко вперед, если файл большой, а ваша обработка медленная- ваша программа может попытаться прочитать гигабайты данных из файла, обработав только первые несколько килобайт.Нет смысла читать данные намного раньше, чем их обрабатывать - вы действительно хотите прочитать немного заранее.Вы можете использовать свойство BlockingCollection<T>
BoundedCapacity
для регулирования количества вещей - если вы установите это значение для какого-то числа, то вызов Add
заблокируется, если в коллекции уже есть такое количество строк, и ваш поток чтенияне будет продолжаться до тех пор, пока цикл обработки не обработает следующую строку.
Было бы интересно сравнить производительность программы, использующей двухпоточный метод, с той, которая просто считывает строки из файла и обрабатывает их впетля на одной нити.Здесь вы сможете увидеть, какую пользу вы получите от многопоточного подхода.
Кстати, если ваша обработка сильно загружает процессор, вы можете использовать вариант этой темы, чтобы иметь несколько потоков обработки (и до сих пор единственная ветка для чтения файлов), потому что BlockingCollection<T>
совершенно счастлив, что многочисленные потребители все читают из коллекции.Конечно, если порядок, в котором вы заканчиваете обработку строк файла, имеет значение, это не вариант, потому что, хотя вы начнете обработку в правильном порядке, если у вас несколько потоков обработки, возможно, что один потокможет настигнуть другого, что приведет к неправильному завершению.