C # - живой текстовый канал из одного потока в другой - PullRequest
3 голосов
/ 01 декабря 2010

В потоке «A» я хочу прочитать очень длинный файл, и когда это произойдет, я хочу отправить каждую прочитанную новую строку в другой поток «B», который будет что-то делать с ними. *

По сути, я не хочу ждать окончания загрузки файла, прежде чем начать обработку строк. (Я определенно хочу, чтобы 2 темы и общение между ними; я никогда не делал этого раньше, и я хочу учиться)

Итак, как мне это сделать? Поток A должен дождаться, пока поток B завершит обработку «текущей строки», прежде чем поток A отправит другую строку в поток B. Но это не будет эффективным; так как насчет буфера в потоке B? (чтобы поймать строки)

Также, пожалуйста, приведите пример того, какие методы я должен использовать для этого межпоточного взаимодействия, так как я не нашел / не увидел никаких полезных примеров.

Спасибо.

1 Ответ

4 голосов
/ 01 декабря 2010

Прежде всего, не ясно, что два потока обязательно будут здесь полезны.Один поток, считывающий по одной строке за раз (что довольно просто при 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> совершенно счастлив, что многочисленные потребители все читают из коллекции.Конечно, если порядок, в котором вы заканчиваете обработку строк файла, имеет значение, это не вариант, потому что, хотя вы начнете обработку в правильном порядке, если у вас несколько потоков обработки, возможно, что один потокможет настигнуть другого, что приведет к неправильному завершению.

...