Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.85/34: Рейтинг темы: голосов - 34, средняя оценка - 4.85
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107

Parallel.ForEach эффективное использование

29.10.2018, 20:01. Показов 7996. Ответов 72

Студворк — интернет-сервис помощи студентам
Хотелось бы услышать реальный опыт использования параллельных циклов и плюсы от использования, если они есть.
Как я понимаю такие циклы надо завязывать на количество ядер процессора.
Общий обычный цикл, а внутри параллельные по количеству ядер.
Кусок кода "внутреннего цикла" внизу оч долгой работы > 5 ч.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Parallel.ForEach(current, (r) =>
                    {
                        currentData = Path.Combine(baseFolder, Path.GetFileNameWithoutExtension(r));
                        Directory.CreateDirectory(currentData);
                        using (ArchiveFile rar = new ArchiveFile(r))
                        {
                            rar.Extract(currentData);
                        }
 
                        foreach (var s in Directory.EnumerateFiles(currentData, "*.*", SearchOption.AllDirectories))
                        {
                            if (Path.GetExtension(s) == ".pdf")
                            {
                                iTextPdf.ExtractTextPdf(s);
                                File.Delete(s);
                            }
                            else
                                File.Delete(s);
                        }
 
                        Utils.CopyFolderContents(currentData, outData);
                        Directory.Delete(currentData, true);
                    });
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
29.10.2018, 20:01
Ответы с готовыми решениями:

Распараллеливание. Parallel.ForEach
На данный момент выполняется такой код: Hashtable files2copy; void startButton_Click(object sender, RoutedEventArgs e) { ...

Parallel.Foreach изменение коллекции
Если коллекция Dictionary<string,Class> dic; Первый поток добавляет и удаляет элементы из коллекции используя Parallel.Foreach Второй...

Pause и Resume в Parallel.Foreach
Сделал пробный проект, в котором идет просто вывод переменной из List<int>. При нажатии на кнопку Button2 переменной isPaused...

72
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
01.11.2018, 15:39  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Woldemar89 Посмотреть сообщение
У меня нет потребности что-либо доказывать, просто вы говорите о параллельности,
А для вас что означает параллельность? Я вам только что описал параллельное считывание и запись двух файлов.
А вы как видите параллельную операцию любую напишите пример чтоб я понял.
0
TheGreatCornholio
 Аватар для Woldemar89
1255 / 733 / 285
Регистрация: 30.07.2015
Сообщений: 2,408
01.11.2018, 16:23
перефразирую пример Эрика Липперта со SO:

Вам нужно приготовить бутерброд:
Поджарить хлеб в тостере - 3 минуты
Нарезать колбасу - 5 минут

Синхронная модель
(один поток - вы):
Вы включаете тостер, ждете пока он приготовит хлеб, режете колбасу
3+5 = 8 минут и бутерброд готов

Асинхронная модель
(один поток - вы):
Смотреть, как тостер готовит хлеб необязательно, значит эта операция может быть выполнена асинхронно (как IO операция(ввода\вывода) IO-bound)
Резка колбасы не может быть выполнена в асинхронном режиме, но может быть выполнена другим работником (в отдельном потоке, CPU-bound) - об этом в параллельной модели

Ставите хлеб в тостер, включаете, начинаете резать колбасу
Когда тостер выплюнул хлеб, прерываете резку колбасы, достаете хлеб (5 секунд), дорезаете колбасу
5 минут 5 секунд и бутерброд готов

Параллельная модель (два потока - вы и ваша собака):
Вы режете колбасу, собака жарит тост
5 минут (наибольшее время среди работы 2х потоков) и бутерброд готов
Но ресурсов затрачено в 2 раза больше (2 работника)

Добавлено через 3 минуты
Вам нужно понять, что операции чтение записи на диск IO-bound и должны выполняться асинхронно
Операции разархивирования, парсинга PDF - CPU-bound и должны бы распараллелены

Таким образом

Цитата Сообщение от Woldemar89 Посмотреть сообщение
Сделайте чтение с диска однопоточным и помещайте данные в очередь (возможно ограниченного размера)
на обработку, а вот ее уже параллельте как вам угодно любыми средствами.
Записи на диск тоже касается - желательно чтобы и чтение и запись на диск обрабатывал один поток асинхронно.
0
Эксперт .NET
 Аватар для Wolfdp
3788 / 1765 / 371
Регистрация: 15.06.2012
Сообщений: 6,543
Записей в блоге: 3
01.11.2018, 16:27
rams, ответе все же на вопрос поставленый выше: какой тип даных и их обьем обрабатывается?

Если ооооочерь хочется разобратся что к чему: читайте доку по Parallel.ForEach. Если кратко, даный зверь юзает TaskScheduler, который в свою очередь общается с пулом потоков приложения. Из того что я видел при работе с ним:
- на старте пулл держит колекцию потоков равную количеству логических процессоров (потоков отображаемых в диспечере задач).
- если какая-то задача занимает очень долго время юзания потока из пула, создается еще один поток для выполения следующей задачи. Процесс создания вообще не шустрый
- если задача очень долгая, и насоздавать условных 100 потоков, то просядите на переключении между ними.
И єто только то что я задел поверхностно, расматривая паралелизацию определеных процесов.

Цитата Сообщение от rams Посмотреть сообщение
Как видно если просто заменить обычный цикл на паралл время выполнения только увеличивается
Создание нового потока -- дорогая операция. Плюс это все потом нужно слкеить. Плюс современые процессоры внутри себя уже "распаралеливают" даже синхроные операции. Как правило для малых операций прирост ощутим только с 100к итераций.

По вашей же задачи: rar.Extract явно отьедает основное время и нужно смотреть реализацию ArchiveFile, и уже плясать от нее. В идеале нужно разделить поток считывания и поток обработки, но если там размер файла под 1Гб, будет весело -- в память его не запихнешь, а значит очередь не построишь.
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
01.11.2018, 20:00  [ТС]
Wolfdp,
Все верно вы говорите, и внятного алгоритма когда применять все эти Parllel async await и т. д. нет, за исключением сетевых штук там почти все можно делать async. Причем сами разработчики tpl также ограничиваются общими рекомендациями добавляя в конце что только тест может дать окончательный ответ. И серьезных примеров я не нашел на .net может не там искал.
На с все понятно nvidia cuda и будет тебе счастье. Но сколько времени занимает решить одну и ту же задачу на с и с# в десятки раз больше у меня по крайней мере.
0
309 / 221 / 74
Регистрация: 23.05.2011
Сообщений: 981
01.11.2018, 20:34
rams, я применял Parallel.ForEach года три назад и добивался трёхкратного ускорения
Если хотите, можете меня не слушать.

Цитата Сообщение от Wolfdp Посмотреть сообщение
но если там размер файла под 1Гб, будет весело -- в память его не запихнешь, а значит очередь не построишь.
Судя по тому, что у ТС нормально засовывается в память по экземпляру на поток, можно запихнуть несколько файлов. Возможно, очередь из 3 элементов, например.

Добавлено через 9 минут
Wolfdp, вообще, скорее всего есть какая-то библиотека, которая умеет один архив параллельно распаковывать из памяти в память.
Я бы смотрел в эту сторону.
Что-то вроде такого псевдокода:
C#
1
2
3
4
5
6
7
8
9
10
11
12
Task<byte[]> loaded_file = null;
List<Task> write_tasks = new List<Task>();
foreach(string filename in files)
{
   byte[] archived = loaded_file?.Result;
   loaded_file = ReadFileAsync(filename);
   if(archived==null)
       continue;
   List<Pair<string, byte[]>> unpacked = ParallelUnZip(archived, GetComputerCoreCount());
   Task wr = WriteMyFilesAsync(updacked);
   write_tasks.Add(wr);
}
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
01.11.2018, 21:26  [ТС]
Цитата Сообщение от New man Посмотреть сообщение
Если хотите, можете меня не слушать.
Почему не слушать можете код дать посмотреть там уж я сам соображу тем более в 3 раза у меня 25% максимальный прирост при любых вариантах

Добавлено через 40 минут
А задача простая и уже давно решена просто я ищу возможности выполнять ее быстрее.
Коротко есть rar архивы 50 -70 шт не большие 40 - 80 мб в них pdf 100 - 200 шт.
Нужно извлечь текст из каждой страницы pdf и сохранить как текстовый файл.
В .net нет нативных средств для работы с rar и pdf так что используются сторонние библиотеки iText и SevenZipExactor
0
309 / 221 / 74
Регистрация: 23.05.2011
Сообщений: 981
02.11.2018, 00:28
rams, бросай программирование. Это не твоё.
Я ни разу не работал с 7z, но разобрался и написал почти рабочую прогу за 20 минут.
Тебе надо было лишь почитать очень короткую документацию.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
    class FileLoader
    {
        private Thread worker;
        private readonly string[] filenames;
        readonly ConcurrentQueue<Tuple<string, Stream>> queue;
        private long finished;
        public bool Finished => Interlocked.Read(ref finished) != 0 && queue.IsEmpty;
        public FileLoader(IEnumerable<string> files)
        {
            filenames = files.ToArray();
            queue = new ConcurrentQueue<Tuple<string, Stream>>();
            worker = new Thread(LoadFiles);
            worker.Start();
        }
 
        private void LoadFiles()
        {
            foreach (string n in filenames)
                using (Stream fs = File.OpenRead(n))
                {
                    MemoryStream ms = new MemoryStream();
                    fs.CopyTo(ms);
                    ms.Seek(0, SeekOrigin.Begin);
                    queue.Enqueue(new Tuple<string, Stream>(n, ms));
                }
            Interlocked.Exchange(ref finished, 1);
        }
 
        public Tuple<string, Stream> GetNext()
        {
            Tuple<string, Stream> result = null;
            if (queue.TryDequeue(out result))
                return result;
            return null;
        }
    }
 
    class Unzipper
    {
        FileLoader loader;
        public Unzipper(FileLoader fl)
        {
            loader = fl;
            Parallel.For(0, 10, _=>Handler());
        }
 
        private Dictionary<string, Stream> results = new Dictionary<string, Stream>();
        public IReadOnlyDictionary<string, Stream> Results
        {
            get
            {
                lock (results)
                    return new Dictionary<string, Stream>(results);
            }
        }
        private void Handler()
        {
            while (!loader.Finished)
            {
                Tuple<string, Stream> rar = loader.GetNext();
                if (rar != null)
                    UnZip(rar.Item1, rar.Item2);
                else
                {
                    if (!loader.Finished)
                        Thread.Sleep(5);
                }
            }
        }
        private void UnZip(string archiveName, Stream stream)
        {
            List<string> paths = new List<string>();
            List<Stream> data = new List<Stream>();
            using (ArchiveFile af = new ArchiveFile(stream))
                foreach (Entry entry in af.Entries)
                {
                    string f = entry.FileName;
                    if (f.Substring(f.Length - 4) != ".pdf")
                        continue;
                    MemoryStream ms = new MemoryStream();
                    entry.Extract(ms);
                    ms.Seek(0, SeekOrigin.Begin);
 
                    // Я не стал за тебя читать документацию к IText, так что сам узнай, как там сделать вывод в Stream
                    IText itext = = new IText(ms);
                    MemoryStream text = new MemoryStream();
                    itext.ExtractTextPdfToStream(text);
                    text.Seek(0, SeekOrigin.Begin);
                    
                    paths.Add(Path.Combine(archiveName, f));
                    data.Add(text);
                }
            lock (results)
            {
                for (int i = 0; i < paths.Count; ++i)
                    results[paths[i]] = data[i];
            }
        }
 
    }
 
    class Program
    {
        public static void Main(string [] args)
        {
            FileLoader loader = new FileLoader(args);
            Unzipper unzipper = new Unzipper(loader);
            foreach(KeyValuePair<string, Stream> res in unzipper.Results)
            {
                string path = Path.Combine("Output", res.Key);
                using (Stream f = File.Create(path))
                {
                    res.Value.CopyTo(f);
                }
            }
        }
    }
Добавлено через 13 минут
Поясняю, что происходит.
В отдельном потоке я считываю данные с диска и кладу в потокобезопасную очередь.
Считываю до конца один файл и только потом пытаюсь открыть друго.

Запускаю до 10 параллельных распаковщиков (думаю, .Net запустит ровно столько, сколько ядер). Каждый из них берёт загруженный в память файл и распаковывает из него только pdf, причём распаковывает тоже напрямую в память, потому что насиловать диск не нужно. Потом из памяти сразу же конвертирует pdf в текстовый поток и сохраняет это в память.

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

Добавлено через 17 минут
В итоге то, что быстрее работает параллельно, считается параллельно.
То, что быстрее работает последовательно, работает последовательно.
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
02.11.2018, 00:31  [ТС]
Я тебя просил код показать Parallel.For который в 3 раза быстрее, чем обычный.
Предвижу ответ потерялся, не помню и т.д.
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,915
02.11.2018, 06:51
rams, Parallel.ForEach не волшебная палочка-ускорялочка. Всё, что данный метод делает - выполняет полученный делегат в N потоков для обработки коллекции. Тоже самое можно сделать и вручную, с помощью Task.Run.

Чтобы это работало быстрее последовательной обработки, вам нужно понимать и думать, что вы делаете. А ваш пример такое понимание не демонстрирует. Вы в N потоков обращаетесь к одному ресурсу - жёсткому диску. Параллельная работа жёсткого диска (или SSD) - только видимость, создаваемая операционной системой.

Вы можете и в сто потоков работать с диском, но на каждый поток будет приходиться одна сотая пропускной способности, плюс расходы на общение с диском, плюс расходы на переключения контекстов потоков. Т.е. работать с диском параллельно не имеет смысла, ибо работа такая будет длиться дольше, чем синхронная.

New man, наличие Thread.Sleep в цикле делает вашу реализацию... не особо эффективной. Все потоки будут крутиться в бесконечном цикле ожидая появления загруженного файла... Для эффективной реализации consumer-producer можно использовать BlockingCollection<T> или произвольную коллекцию в связке с ManualResetEventSlim. А бесконечные циклы в связке с Thread.Sleep - фу неописуемое.
0
02.11.2018, 11:36

Не по теме:

Usaga, не тратьте время в этой теме - тут слой железобетона несколько метров походу.

0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
02.11.2018, 12:30  [ТС]
Usaga, Вот тесты посмотрите может я что то не так делаю, но StopWatch показывает что не все так однозначно.
Woldemar89, Пожалуйста не надо флудить здесь люди пытаются разобраться и найти оптимальное решение я так полагаю.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
 
namespace ConAppPdf
{
    class Program
    {
        const string folder = @"E:\Downloads\ЭР-Телеком";
 
        static void Main(string[] args)
        {
            TestReadFilesСonsistently(folder);
            TestReadFilesParallel(folder);
            Console.Read();
        }
        public static void TestReadFilesСonsistently(string dirName)
        {
            Stopwatch w = new Stopwatch();
            w.Start();            
 
            foreach (var s in System.IO.Directory.EnumerateFiles(dirName, "*.pdf", System.IO.SearchOption.AllDirectories))
            {
                using (FileStream f = new FileStream(s, FileMode.Open, FileAccess.Read))
                {
                    MemoryStream m = new MemoryStream();
                    f.CopyTo(m);
                }
            }           
 
            w.Stop();
            Console.WriteLine("TestReadFilesСonsistently successful complete. Time {0}", w.Elapsed);
        }
        public static void TestReadFilesParallel(string dirName)
        {
            Stopwatch w = new Stopwatch();
            w.Start();
 
            List<string> files = System.IO.Directory.EnumerateFiles(dirName, "*.pdf", System.IO.SearchOption.AllDirectories).ToList();
            List<string> current = new List<string>();
 
            int i = 0;
            int count = 0;
            int step = Environment.ProcessorCount;//amount cores            
            int iter = files.Count / step;
 
            if (iter != 0)
            {
                for (i = 0; count < iter; i += step)
                {
                    current = files.GetRange(i, step);
 
                    Parallel.ForEach(current, (p) =>
                    {
                        using (FileStream f = new FileStream(p, FileMode.Open, FileAccess.Read))
                        {
                            MemoryStream m = new MemoryStream();
                            f.CopyTo(m);
                        }
                    });
 
                    count++;
                }
            }
 
            int remainder = files.Count % step;
 
            if (remainder != 0)
            {
                current = files.GetRange(i, remainder);
 
                Parallel.ForEach(current, (p) =>
                {
                    using (FileStream f = new FileStream(p, FileMode.Open, FileAccess.Read))
                    {
                        MemoryStream m = new MemoryStream();
                        f.CopyTo(m);
                    }
                });
            }
 
            w.Stop();
            Console.WriteLine("TestReadFilesParallel successful complete. Time {0}", w.Elapsed);           
        }
    }
}
0
Эксперт .NET
 Аватар для Usaga
14086 / 9303 / 1348
Регистрация: 21.01.2016
Сообщений: 34,915
02.11.2018, 12:48
rams, мне не зачем смотреть на результаты бенчмарков, когда невооружённым глазом видно "фу".

Цикл с Thread.Sleep внутри не нужно оправдывать. Это нужно исправлять.
0
309 / 221 / 74
Регистрация: 23.05.2011
Сообщений: 981
02.11.2018, 12:54
Цитата Сообщение от Usaga Посмотреть сообщение
producer можно использовать BlockingCollection<T> или произвольную коллекцию в связке с ManualResetEventSlim. А бесконечные циклы в связке с Thread.Sleep - фу неописуемое.
I know.

Проблема в том, что я ни разу не писал consumer-producer на C#, т.к. в основном я пишу на C++, а лезть разбираться в документацию в этой теме незачем.
Впрочем, спасибо, теперь я знаю, что гуглить.
Ну, и если это тебя успокоит
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
readonly BlockingCollection<Tuple<string, Stream>> queue;
//....
Interlocked.Exchange(ref finished, 1);
queue.CompleteAdding();
 
 
private void Handler()
{
    while (!loader.Finished)
    {
          Tuple<string, Stream> rar = null;
          try{
               rar = loader.Take();
          }
          catch(InvalidOperationException){}
          if (rar != null)
                UnZip(rar.Item1, rar.Item2);
        }
}
rams, эээ, Вы это серьёзно вообще? Тебе тут помочь пытаются, между прочим.
А мой код прост. Интересно, что он тебе даст:
C#
1
2
3
4
Parallel.For(0, Basises.Count, j =>
{
     res[j] = Analyze(TruthTable, Basises[j]);
});
Добавлено через 5 минут
Цитата Сообщение от rams Посмотреть сообщение
C#
1
2
3
4
5
6
7
Parallel.ForEach(current, (p) => 
{ 
using (FileStream f = new FileStream(p, FileMode.Open, FileAccess.Read)) 
{ 
     MemoryStream m = new MemoryStream(); 
     f.CopyTo(m); } 
});
Сколько раз тебе надо говорить, что так делать нельзя? Тебе уже раз пять объясняли в этой теме.
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
02.11.2018, 13:04  [ТС]
New man, Вот ваш код
C#
1
2
3
4
5
6
7
 using (Stream fs = File.OpenRead(n))
                {
                    MemoryStream ms = new MemoryStream();
                    fs.CopyTo(ms);
                    ms.Seek(0, SeekOrigin.Begin);
                    queue.Enqueue(new Tuple<string, Stream>(n, ms));
                }
Вы берете архив копируете его в память потом снова открываете

C#
1
2
3
 using (ArchiveFile af = new ArchiveFile(stream))
                foreach (Entry entry in af.Entries)
                {
вопрос зачем? это же время сразу не проще
потом мне говорите что надо документацию читать а там сказано зачем нужен такой конструктор
когда скачиваешь файл из интернета и пример приведен здесь это оправдано можно не сохранять
архив а сразу распаковывать.

C#
1
2
3
4
5
6
7
WebRequest request = WebRequest.Create ("http://www.contoso.com/file.aspx?id=12345");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 
using (ArchiveFile archiveFile = new ArchiveFile(response.GetResponseStream())
{
    archiveFile.Extract("Output"); 
}
А вы делаете лишнюю работу еще раз спрошу зачем.
И дайте нормальный пример смысл вырвать строчку из кода и показать.
0
1 / 2 / 0
Регистрация: 02.06.2018
Сообщений: 33
02.11.2018, 13:11
Нужно не распараллеливать, а совмещать операции распаковки и записи на диск.
Распаковка –синхронная операция. Кстати можете распараллелить по ядрам саму распаковку, чтение исходников с диска не распараллелится. Запись производить асинхронно. Т.е распаковали один файл, отдали на запись асинхронному сервису, распаковываете другой файл и т.д.
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
02.11.2018, 13:32  [ТС]
B_S_V, Ок то есть вы предлагаете
Распаковал файл в память -> async func вся работа с pdf ()
Правильно понял? Согласен надо пробовать сделаю.
0
1 / 2 / 0
Регистрация: 02.06.2018
Сообщений: 33
02.11.2018, 14:13
Нужно распланировать ядра процессора. Предположим у вас 4 ядра.
На первом ядре делаем синхронный сервис чтения сжатых файлов.
На двух следующих открываем два асинхронных сервиса распаковки.
На последнем ядре делаем асинхронный сервис записи на диск

int CREATE_SERVICE(string name, object method, int core,i nt isProcess)

CREATE_SERVICE (“Read,” object methodRead , 0 , 0)
CREATE_SERVICE_ASYNC ( “UnPack_1”, methodUnPack, 1, 0)
CREATE_SERVICE_ASYNC (UnPack_2”, methodUnPack, 2, 0)
CREATE_SERVICE_ASYNC ( “Write”, methodWrite , 3 ,0)

Сервис Read читает файлы и передает их поочередно в один из двух асинхронных серверов распаковке. Те распаковывают и передают файл в асинхронный сервис записи на диск.
0
309 / 221 / 74
Регистрация: 23.05.2011
Сообщений: 981
02.11.2018, 14:27
Цитата Сообщение от rams Посмотреть сообщение
Вы берете архив копируете его в память потом снова открываете
Нет.
Я сначала копирую байты с диска в оперативную память, потом открываю память как архив.
Время между чтением байта с памяти в сотни раз быстрее чем с диска, поэтому процесс идёт быстрее.
+ мы можем параллельно читать с диска и распаковывать.

У тебя же сначала n потоков одновременно читают с диска, потом они уже одновременно пытаются распаковать.

Чтение с диска почти не тратит ресурсы процессора, но тратит ресурс системной шины, сдвигов головки и т.п.
Распаковка же тратит в основном ресурсы процессора.

В итоге твой код сначала сильно загружает диск, причём очень неоптимально (потому что читать последовательно с диска по одному файлу намного быстрее, чем много файлов параллельно), но заставляет простаивать проц.
Потом у тебя простаивает диск но перегружается проц.
Потом у тебя опять перегружается диск.

В общем, оптимизировать тебе надо именно работу с диском, используя MemoryStream вместо FileStream на всех этапах кроме самого первого чтения и последней записи. Потому что работа с памятью напрямую в сотни раз быстрее.
Потом надо параллелить распаковку pdf и выделение текста из PDF, причём работать надо только в ОЗУ, потому что файлы у тебя помещаются.
0
24 / 24 / 5
Регистрация: 04.04.2012
Сообщений: 107
02.11.2018, 14:40  [ТС]
Цитата Сообщение от B_S_V Посмотреть сообщение
Нужно распланировать ядра процессора. Предположим у вас 4 ядра.
А как вы так хотите, а если 2.
Все что я имею Environment.ProcessorCount;//amount cores узнать количество ядер.
И их 2 например и что делать?
0
309 / 221 / 74
Регистрация: 23.05.2011
Сообщений: 981
02.11.2018, 14:43
Цитата Сообщение от rams Посмотреть сообщение
когда скачиваешь файл из интернета и пример приведен здесь это оправдано можно не сохранять
Это пример.
Автор документации не думал, что тебе нужно будет сотни файлов параллельно распаковывать.

Добавлено через 1 минуту
Цитата Сообщение от rams Посмотреть сообщение
И их 2 например и что делать?
Юзать ThreadPool.
Или Parallel.For
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
02.11.2018, 14:43
Помогаю со студенческими работами здесь

PLINQ или Parallel.ForEach?
Пытаюсь сообразить как лучше сделать задачку. Есть большой список EXCEL файлов и мне надо их считать проделать некоторые операции (все...

Parallel.ForEach и его неадекватное поведение
Задача простая. Я выполняю какие либо действия, в результате чего у меня появляется допустим огромный массив с данными, которые мне нужно...

Parallel.ForEach что не верно? Не компилируется
class Program { static void Main(string args) { ParallelOptions parOpt = new ParallelOptions(); ...

Сравнение списков Parallel.ForEach неадекватный результат
Сравниваю два списка, возвращаю первое совпадение. Но возвращаемое значение всегда разное при одинаковых списках. В чем может заключаться...

Parallel foreach ожидание для каждого потока
Добрый день. Есть Parallel.ForEach, который внутри себя вызывает json запрос на сервер. Parallel.ForEach(arr, v =&gt; { ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru