Страницы

Поиск по вопросам

четверг, 13 февраля 2020 г.

Многопоточность для обработки файла

#c_sharp #net #многопоточность


Есть много огромныйх файлов(по 4-6gb), мне нужно запустить примерно 100 потоков,
чтобы каждый поток брал следующую строку из файла и обрабатывал.

        List _threads;
        int countThr;

        public void Run(int count)
        {
            Globals.threadAlive = 0;
            _threads = new List();
            _threads.Clear();
            countThr = count;
            for (int i = 0; i < count; i++)
            {
                var thread = new Thread(multiThread);
                thread.IsBackground = true;
                _threads.Add(thread);
                _threads[i].Start();
            }
        }

        public void Abort()
        {
            Globals.threadAlive = 1;
            foreach (Thread thr in _threads)
            {
                thr.Abort();
            }
            _threads.Clear();
            Globals.threadAlive = 0;
        }

        private void multiThread()
        {
            for (int c = 0; c < Globals.lines.Length; c++)
            {
                //обработка строки
            }
            Globals.threadAlive = 1;
            Abort();
        }


Это будет правильное решение моей задачи?
    


Ответы

Ответ 1



Я предлагаю вычитывать с помощью File.ReadLines, это позволяет не загружать весь файл в память. Разбирать отдельные строки в отдельных задачах для потоков - нерентабельно, скорее всего, зависит от того, как долго занимает обработка одной строки. Поэтому предложенный вариант разбивает все строки на пакеты небольшого размера (batches) и обрабатывает их параллельно. void Main() { var filePath = Path.GetTempFileName(); File.WriteAllText(filePath, string.Join(Environment.NewLine, Enumerable.Range(0, 100001))); var batchSize = 1000; var allLines = File.ReadLines(filePath); var processedCount = 0; GetLinesInBatches(allLines, batchSize).AsParallel().ForAll(batch => { foreach (var line in batch) { Interlocked.Increment(ref processedCount); // Do something with the line. } }); Console.WriteLine("Total: {0}", processedCount); } IEnumerable> GetLinesInBatches(IEnumerable allLines, int batchSize) { using (var e = allLines.GetEnumerator()) { bool more = false; do { var batch = new List(batchSize); for (var i = 0; i < batchSize && (more = e.MoveNext()); i++) { batch.Add(e.Current); } yield return batch; } while (more); } }

Ответ 2



Если у вас доминирует чтение файла, просто читайте каждый из файлов в одном отдельном потоке. Сотня потоков не нужна и только всё испортит. Да, и потоки устарели уже давно, применяйте TPL. void ProcessFile(string path) { foreach (var line in File.ReadLines(path)) { // обработать строку } } IEnumerable paths = ...; var processTasks = paths.Select(p => Task.Run(() => ProcessFile(p)); await Task.WhenAll(processTasks); Ленивое чтение файла позволяет не грузить гигабайты текста в память. Заодно убрали ненужную (и ошибочную) ручную работу с потоками. Если у вас обработка строки занимает ощутимое время, вам пригодится PFX: void ProcessFile(string path) { Parallel.ForEach(File.ReadLines(path), line => { // обработать строку }); }

Комментариев нет:

Отправить комментарий