многопоточное чтение и обработка больших текстовых файлов - PullRequest
1 голос
/ 09 марта 2012

У меня есть 10 списков по 100 МБ каждый с электронными письмами, и я хочу обрабатывать их с использованием многопоточности как можно быстрее и без загрузки их в память (что-то вроде чтения построчно или чтения небольших блоков)создал функцию, которая удаляет недопустимые на основе регулярных выражений, и другую, которая организует их на основе каждого домена в другие списки.

Мне удалось сделать это, используя один поток с: while (reader.Peek ()! = -1), но это занимает слишком много времени.

Как я могу использовать многопоточность (около 100 - 200) и, может быть, фоновый работник или что-то, чтобы иметь возможность использовать форму при параллельной обработке списков?

Я новичок в csharp: P

Ответы [ 4 ]

5 голосов
/ 09 марта 2012

Если данные не находятся на нескольких физических дисках, есть вероятность, что процесс будет замедлен не более чем несколькими потоками, а не ускорит процесс.

То, что произойдет, это то, что вместо чтения последовательных данных (довольно быстро), вы в конечном итоге будете искать в одном месте для чтения данных для одного потока, затем искать в другом месте для чтения данных для другого потока и т. Д. , Поиск относительно медленный, поэтому он заканчивается медленнее - часто намного медленнее.

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

2 голосов
/ 09 марта 2012

Есть несколько подходов к этому:

1.) Вы можете явно создавать потоки, такие как Thread t = new Thread (), но такой подход дорог при создании и управлении потоком.
2.) Вы можете использовать .net ThreadPool и передать адрес исполняемой функции статическому методу QueueUserWorkItem класса ThreadPool. Этот подход требует ручного управления кодом и примитивами синхронизации.
3.) Вы можете создать массив System.Threading.Tasks.Task, каждый из которых обрабатывает список, который выполняется параллельно, используя все доступные на компьютере процессоры, и передает этот массив в task.WaitAll (Task []), чтобы дождаться их завершения. , Этот подход связан с параллелизмом задач, и вы можете найти подробную информацию по MSDN

Task[] tasks = null;
for(int i = 0 ; i < 10; i++)
{
     //automatically create an async task and execute it using ThreadPool's thread
     tasks[i] = Task.StartNew([address of function/lambda expression]);
}

try
{
    //Wait for all task to complete
    Task.WaitAll(tasks);
}
catch (AggregateException ae)
{
    //handle aggregate exception here
    //it will be raised if one or more task throws exception and all the exceptions from defaulting task get accumulated in this exception object
}

//continue your processing further
1 голос
/ 09 марта 2012

Вам захочется взглянуть на Task Parallel Library (TPL) .

Эта библиотека фактически предназначена для параллельной работы. Он будет выполнять ваши действия в Threadpool любым наиболее эффективным способом (как правило). Единственное, что я хотел бы предостеречь, это то, что если вы запускаете 100-200 потоков одновременно, то вам, возможно, придется столкнуться с переключением контекста. То есть, если у вас нет 100-200 процессоров. Хорошее практическое правило - запускать столько параллельных задач, сколько у вас есть процессоров.

Некоторые другие полезные ресурсы для обзора того, как использовать TPL:

Почему и как использовать TPL Как запустить задачу.

0 голосов
/ 09 марта 2012

Я был бы склонен использовать параллельный linq (plinq).

Что-то вроде:

Lists.AsParallel () .SelectMany (list => list) .Где (MyItemFileringFunction) .GroupBy (DomainExtractionFunction)

AsParallel говорит linq, что он может делать это параллельно (что будет означать, что упорядочение всего следующего не будет поддерживаться)

SelectMany берет ваши индивидуальные списки и разворачивает их так, что все все элементы из всех списков эффективно объединяются в один Перечисляемый

Где хранит элементы, используя вашу функцию предиката

GroupBy собирает их по ключу, где DomainExtractionFunction является функцией, которая получает ключ (имя домена в вашем случае) из элементов (т. Е. Электронной почты)

...