Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.56/18: Рейтинг темы: голосов - 18, средняя оценка - 4.56
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173

Многопоточная обработка мелких файлов

24.06.2014, 21:42. Показов 3561. Ответов 29
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день!

Программа через ThreadPool обрабатывает массив файлов:

C#
1
2
3
4
   foreach (string file in Files)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)file);
                }
Метод Check() читает файл, делает различные проверки, в конце - пишет результаты в таблицу.

Я заметил, что если программа обрабатывает крупные файлы (средним объемом 50 Мб), то скорость работы получается максимально высокой. Если программа обрабатывает мелкие файлы (по 1 Мб), то скорость обработки падает в несколько раз.

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

Добавлено через 1 минуту
Я так понял, что основные затраты состоят в том, что:
- на каждый файл создается отдельный поток;
- в методе check() ведется некая подготовка для чтения файла
- вывод результатов в DataGridView происходит чаще, если если обрабатывать крупные файлы.

Добавлено через 38 минут
В Parallel.ForEach есть такая штука встроенная "Partitioner". Она позволяет не создавать отдельный поток для каждого файла, а создавать один поток, а потом направлять в него некую "порцию" файлов. Таким образом, более эффективно распределяя нагрузку. Я, вот, думаю, можно ли для ThreadPool что-то подобное сделать.

Добавлено через 7 минут
Думаю, как бы в качестве объекта в строку
ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)file);

передавать не один (object)file, а, скажем массив, состоящий из нескольких файлов общим объемом не менее 50 Мб. Если же какой-то файл сразу больше 50 Мб, то передавать только один файл в массиве.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
24.06.2014, 21:42
Ответы с готовыми решениями:

Многопоточная обработка
Здравствуйте! Есть while, который берет записи из базы данных и обрабатывает их с помощью методов класса, а затем результат записывает...

Многопоточная обработка данных + ввод/вывод
Доброго времени суток! Пишу небольшое консольное приложение, и у меня возникли некоторые вопросы. Надеюсь, кто-нибудь мне поможет. ...

Скачивание множества мелких файлов
Почему webClient.DownloadFileAsync на скачивает файлы и программа переходит к следующему методу? Хотя с webClient.DownloadFile все...

29
9 / 9 / 5
Регистрация: 23.06.2014
Сообщений: 40
24.06.2014, 21:44
Можно, есть штука под названием Task - она как раз не создает новый поток, а использует уже существующие.
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
24.06.2014, 21:47  [ТС]
Мне нужно на ThreadPool, т.к. c# 2.0 использую.

Разгадка, скорей всего в последнем абзаце сабжевого поста. То есть нужно делать файлы на массивы из "порций" по 50 Мб, а потом передавать в ThreadPool массивы.
0
9 / 9 / 5
Регистрация: 23.06.2014
Сообщений: 40
24.06.2014, 21:50
И что? передадите 50 файлов по 1 мегабайту, или по 5000 файлов по 10 кб, получите дохера потоков,
которые будут открывать (относительно медленная операция), работать с файлами, и закрывать их(тоже относительно медленная).
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
24.06.2014, 21:56  [ТС]
Нет. Если я не 50 раз передам по файлу в 1 Мб:
C#
1
 ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)file);
а один раз передам массив, состоящий из 50 файлов
C#
1
 ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)arrayOfFiles);
то, по идее, во втором случае один поток будет?
0
9 / 9 / 5
Регистрация: 23.06.2014
Сообщений: 40
24.06.2014, 22:01
Да, разумеется, отработает в одном потоке. Вызываете же один раз
ThreadPool.QueueUserWorkItem
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
24.06.2014, 22:03  [ТС]
Значит, я на верном пути, дон Карлос.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
25.06.2014, 10:03
Suppir, тред пул не создает по потоку на задачу, на то он и тредпул. Поэтому 4 файла по 10 кб или 4 файла по 100мб, будет работать в одно и то же число потоков. Скорее всего, падение скорости связанно со случайным доступом к данным. Вместо того, чтобы гадать, нужно запускать профайлер и смотреть.
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 10:21  [ТС]
Я для теста проверяю 17 тыс. мелких файлов общим объемом 200 Мб.

Был такой код посылания в ThreadPool:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
  foreach (string file in Files)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)file);
                    Thread.Sleep(10);
                }
 
                  lock (WorkerLocker)
                {
                    while (RunningWorkers > 0)
                    {
                        Monitor.Wait(WorkerLocker);
                    }
                }
Время работы - аж 180 секунд (очень медленно).

Сейчас переписал на такой код:

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
   StringBuilder sb = new StringBuilder();
    RunningWorkers = 0;
    int allSize = 0;
    foreach (string file in Files)
    { 
        FileInfo fi = new FileInfo(file);
        int size = Convert.ToInt32(fi.Length);
        allSize += size;
 
        sb.Append("|");
        sb.Append(file);
 
        if (allSize > 1000000)
        {
            allSize = 0;
            RunningWorkers++;
            ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)sb);
            Thread.Sleep(10);
            sb = new StringBuilder();
        }
    }
    if (sb.ToString().Length > 0)
    {
        RunningWorkers++;
        ThreadPool.QueueUserWorkItem(new WaitCallback(RunCheck), (object)sb);
        Thread.Sleep(10);
    }
Время работы - 7 секунд! То есть формирую список файлов из 10 Мб, потом посылаю на функцию.

Не знаю почему, но список через файлом List<string> не получается формировать. Передается всего один файл. Поэтому формирую StringBuilder с названиями файлов, а внутри функции разделяю этот StringBuilder с помощью Split на названия файлов.

Добавлено через 44 секунды
Пока что код косячный, есть разные глюки, но направление, скорее всего, правильное.

Добавлено через 5 минут
Возможно, еще связано с тем, что перед каждой обработкой файла инициируются многие переменные, списки, регулярные выражения - это также отнимает время. Сейчас я делаю эту инициацию не перед каждым из 17000 файлов, а перед 20 "порциями" файлов по 10 Мб. То есть почти в тысячу раз реже. Инициация занимает 5 миллисекунд по тестам. Умножаем на 17 тыс. = 85 секунд простоя.
0
 Аватар для Spawn
995 / 893 / 354
Регистрация: 24.03.2014
Сообщений: 2,381
Записей в блоге: 2
25.06.2014, 10:27
Если там нигде реально долгоиграющих действий нет, то в основном потери будут из-за железа, как и сказал Psilon, из-за случайного доступа к данным. То, что Вы делаете, в данном конкретном случае отработало 7 секунд, при других файлах, размерах, дефрагментированности диска, отработает совсем иначе.
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 10:38  [ТС]
Запускаю на SSD-винчестере. Не знаю, влияет ли там дефрагментация.

Добавлено через 1 минуту
Я не могу только понять, почему не удается формировать List<string> с названиями файлов. Если передаю в ThreadPool, а потом обнуляю (ведь нужно дальше заново формировать), то внутри ThreadPool при перечислении файлов пишет, что список был изменен, перечисление невозможно.

Как думаете, можно ли это исправить?
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
25.06.2014, 10:38
Suppir, тогда странно.

Да и если не себе программа пишется, лучше протестировать на компьютерах с обычным hdd. Потому тут уже в обратную сторону будет работать

Любая программа может работать быстро. Если работает медленно, значит что-то делается не так. Трудно так сходу сказать, что конкретно, но вот наличие этого тупика очевидно.
0
 Аватар для Spawn
995 / 893 / 354
Регистрация: 24.03.2014
Сообщений: 2,381
Записей в блоге: 2
25.06.2014, 10:45
Цитата Сообщение от Suppir Посмотреть сообщение
то внутри ThreadPool при перечислении файлов пишет, что список был изменен, перечисление невозможно
Значит где-то модифицируете коллекцию...
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 10:46  [ТС]
Может быть еще влияет, что стоит:
C#
1
2
ThreadPool.QueueUserWorkItem(new WaitCallback(Check), (object)sb);
            Thread.Sleep(10);
То есть после каждой отправки на тредпул идет пауза. Если умножить на 17 тыс. файлов, получается внушительное время.
0
 Аватар для Spawn
995 / 893 / 354
Регистрация: 24.03.2014
Сообщений: 2,381
Записей в блоге: 2
25.06.2014, 10:49
Ну да, внушительное... а зачем собственно передышка нужна? GUI?
И что вообще с такой кучей файлов делается?
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 10:53  [ТС]
Spawn,

Я пробовал передавать List<string> из файлов следующим образом:

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
                List<string> Partition = new List<string>();
 
                int allSize = 0;
                foreach (string file in Files)
                { 
                    FileInfo fi = new FileInfo(file);
                    allSize += Convert.ToInt32(fi.Length);
 
                    Partition.Add(file);
 
                    if (allSize > 1000000)
                    {
                        allSize = 0;
                        RunningWorkers++;
                        ThreadPool.QueueUserWorkItem(new WaitCallback(RunCheck), (object)Partition);
                        Thread.Sleep(10);
                        Partition.Clear();
                    }
                }
                if (Partition.Count > 0)
                {
                    RunningWorkers++;
                    ThreadPool.QueueUserWorkItem(new WaitCallback(RunCheck), (object)Partition);
                    Thread.Sleep(10);
                }
 
                lock (WorkerLocker)
                {
                    while (RunningWorkers > 0)
                    {
                        Monitor.Wait(WorkerLocker);
                    }
                }

Внутри RunCheck я просто перебираю список файлов. Но там получается, что этот список обнуляется извне. Скорее всего, кодом Patriotion.Clear(), который идет после ThreadPool.QueueUserWorkItem.

Как думаете, можно ли это как-то исправить?

Добавлено через 2 минуты
Цитата Сообщение от Spawn Посмотреть сообщение
Ну да, внушительное... а зачем собственно передышка нужна? GUI?
И что вообще с такой кучей файлов делается?
Отправляется файл на парсер. Затем он проверяется разными сложными функциями, ищутся ошибки, формируется результат в DataTable. В конце обработки файла результат (если есть) пишется в GUI. Также обновляется информация в статусбаре. И еще пауза нужна, чтобы пользователь мог останавливать процесс. Если без паузы отправить сразу все файлы на Threadpool, тогда придется ждать завершения всей обработки.
0
Master of Orion
Эксперт .NET
 Аватар для Psilon
6102 / 4958 / 905
Регистрация: 10.07.2011
Сообщений: 14,522
Записей в блоге: 5
25.06.2014, 10:58
Suppir, пауза в коде - ошибка в коде. Простое правило
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 11:04  [ТС]
Psylon, вы знаете какой-нибудь более правильный вариант для ThreadPool?

Я использую паузу после ThreadPool, потом:

C#
1
2
3
4
5
6
7
    lock (WorkerLocker)
                {
                    while (RunningWorkers > 0)
                    {
                        Monitor.Wait(WorkerLocker);
                    }
                }
А внутри ThreadPool:

C#
1
2
3
4
5
6
 //Ждем завершение треда
            lock (WorkerLocker)
            {
                RunningWorkers--;
                Monitor.Pulse(WorkerLocker);
            }
0
1 / 1 / 0
Регистрация: 20.06.2014
Сообщений: 17
25.06.2014, 13:16
Цитата Сообщение от Suppir Посмотреть сообщение
Внутри RunCheck я просто перебираю список файлов. Но там получается, что этот список обнуляется извне. Скорее всего, кодом Patriotion.Clear(), который идет после ThreadPool.QueueUserWorkItem.
Как думаете, можно ли это как-то исправить?
Можно внутри метода RunCheck делать копию списка Patriotion и перебирать копию. Или сразу передавать копию.
0
28 / 28 / 11
Регистрация: 08.08.2011
Сообщений: 1,173
25.06.2014, 13:22  [ТС]
Я пробовал создать копию внутри RunCheck - примерно то же самое получается.

А как передавать копию? В смысле, присвоить значения другому списку, передать его? Но ведь другой список также придется обнулять. И если он будет в локальной видимости:

C#
1
2
3
4
5
6
7
8
9
if (allSize > 1000000)
                    {
                        allSize = 0;
                        RunningWorkers++;
                        List<string> Copy = new List<string> (Partition) 
                        ThreadPool.QueueUserWorkItem(new WaitCallback(RunCheck), (object)Copy);
                        Thread.Sleep(10);
                        Partition.Clear();
                    }
И если этот список Copy будет в локальной видимости, то он сам уничтожится после передачи в ThreadPool. Проблема, как я понял, в том, что ThreadPool отрабатывает моментально, а сразу за ним идет обнуление списка с файлами.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
25.06.2014, 13:22
Помогаю со студенческими работами здесь

Многопоточная обработка списка
Друзья, подскажите, пожалуйста, правильно ли я делаю. Задача: Я реализовал это следующим образом: Проблема в том, что...

Многопоточная обработка массива
В общем, есть два задания: 1. Реализуйте последовательную обработку элементов вектора, например, умножение элементов вектора на число....

Многопоточная обработка структур
Прошу сильно не ругать. Нужна помощь со студенческим заданием. Задание такое: В работе необходимо реализовать многопоточную обработку ...

Многопоточная обработка файла
Всем доброго времени суток! У меня есть задача параллельной обработки файла некоторым алгоритмом. Решил это дело организовать по...

c# многопоточная обработка транзакций
Мне нужно максимально быстро обработать некоторое кол-во транзакций (от 1 до нескольких тысяч). Функция для обработки уже есть. Как...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при создании или изменении элементов справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи электронной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru