12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
||||||
1 | ||||||
Многопоточная генерация сигнатуры файла15.01.2017, 12:30. Показов 2491. Ответов 12
Метки нет (Все метки)
Здравствуйте. Подскажите как лучше решить задачу и в каком направлении копать. С многопоточностью практически не знаком.
Есть задание:
0
|
15.01.2017, 12:30 | |
Ответы с готовыми решениями:
12
Многопоточная загрузка файла Генерация сигнатуры файла. Потеря памяти Проверка сигнатуры файла Многопоточная обработка файла |
12073 / 8383 / 1280
Регистрация: 21.01.2016
Сообщений: 31,578
|
|
15.01.2017, 13:30 | 2 |
V0vchik, жёсткому диску наплевать сколько у процессора ядер. У него фиксированная пропускная способность, которую ты поделил на четыре запустив задачу в несколько потоков. С диском работай только в одном потоке (одновременно, я имею в виду).
Я вижу это так: прочитать с диска блок данных (по-больше), и в четыре потока его посчитать (ну, тоесть разбить его на четыре блока). Единственное, что я точно не знаю как можно хеш посчитать многопоточно. Тут я не силён. Может действительно можно сделать так как это раньше делали всякие P2P клиенты типа FlylinkDC++ и ему подобные, когда TTR считали: бить данные на блоки и для каждого в отдельности считать хеш. Это можно и в параллель сделать. Но с диском всёравно нужно в один поток работать.
1
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
|
15.01.2017, 13:45 [ТС] | 3 |
Usaga, ок, попробую. Спасибо за советы. Сейчас возникла мысль читать одним потоком в небольшой массив который будет очередью блоков, а из него уже остальными потоками брать данные по очереди и их обрабатывать. Правда я не знаю на сколько это удачная идея. Уже начал тестировать эту задумку.
0
|
12073 / 8383 / 1280
Регистрация: 21.01.2016
Сообщений: 31,578
|
|
15.01.2017, 14:09 | 4 |
V0vchik, лучше создать четыре потока-воркера (worker), и один объект-поставщик данных. Все потоки будут к нему ломиться за данными, а он будет поочерёдно считывать данные блоками (по одному) и раздавать воркерам. Получится, что пока поставщик считывает новый блок над предыдущим (предыдущими) уже ведётся работа. Распараллеливание получается лучше, чем все потоки будут дружно ждать данных.
Добавлено через 5 минут Это классическая задача Producer-Consumer. Реашется массой разных способов. Вот есть некоторые примеры. Но можно нагуглить ещё пару-тройку миллионов.
1
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
|
15.01.2017, 14:13 [ТС] | 5 |
Usaga, это тоже обязательно попробую, но с начала хочу потестить какой результат даст эта задумка. Спасибо.
0
|
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
|
|
15.01.2017, 16:36 | 6 |
V0vchik, я писал решение для такой задачи под .Net 3.5. Правда я его мало тестировал. Можете посмотреть решение тут: https://github.com/UnresolvedE... eSignature
Решение было навеяно этой темой: Прошу консультации экспертов (ООП, многопоточность)
1
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
||||||
16.01.2017, 05:20 [ТС] | 7 | |||||
TopLayer, пока не смог разобрать ваш пример, как и многие из той темы. Явно не хватает знаний
Со 2 попытки вышло не лучше чем в первый раз:
0
|
12073 / 8383 / 1280
Регистрация: 21.01.2016
Сообщений: 31,578
|
|
16.01.2017, 06:30 | 8 |
V0vchik, тут синхронизация не обязательна. Можно использовать потокобезопасную коллекцию типа BlockCollection. Погугли примеры её использования, в сети их очень много.
Так же рекомендую переиспользовать блоки данных, чтобы не пересоздавать их каждый раз и не напрягать сборщик мусора. К примеру создать пул блоков (по одному на поток, можно и больше), из которых поставщик данных будет брать свободные блоки, а воркеры будут блоки в пул возвращать. И ещё: вызов GC.Collect() - есть очень плохая практика. GC и без тебя знает, когда ему запуститься. И названия классам давай говорящие. something и todo мало что говорят о предназначении этих сущностей.
0
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
|
16.01.2017, 06:45 [ТС] | 9 |
Usaga, ну это они пока так называются А GC.Collect() тут не просто так. Когда размер блока больше 20мб он не успевает вовремя очиститься. Может потому-что у меня не самый быстрый компьютер, но у меня процесс этого приложения постепенно растет от 100мб до 1гб, потом видимо происходит сборка и он опять растет до 1гб. Это при блоке в 20мб, а если больше там дела совсем плохо. С GC.Collect() все чиститься вовремя. Про BlockCollection почитаю, спасибо
0
|
12073 / 8383 / 1280
Регистрация: 21.01.2016
Сообщений: 31,578
|
|
16.01.2017, 06:52 | 10 |
V0vchik, 20Мб - слишком много. Пары мегабайт вполне себе хватит. И сборка будет чаще и потокам задача в руки попадать чаще будет. А так получается, что все потоки тупо сидят и ждут пока ты 20мб с диска поднимешь только для одного из них. Я больше чем уверен, что поток успеет быстрее обсчитать этот блок, чем этот же блок с диска поднимется.
В общем, перефразирую прошлый пост: если твой код не может нормально работать без GC.Collect(), то такой код - фигня и его нужно переписать. Меньший размер блоков, пул блоков (переиспользование) и всё пучком. Добавлено через 2 минуты Т.е. тебе нужны две потокобезопасные коллекции: одна с данными прочитанными с диска, вторая со свободными блоками под эти самые данные. Получится красивая автоматическая синхронизация: воркеры не начнёт работу, пока в колеекции с данными нет этих данных, а поставщик не будет ничего читать с диска, пока воркеры не вернут хотя бы один блок в пул. Красота же.
0
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
|
17.01.2017, 06:38 [ТС] | 11 |
TopLayer, ваше решение просто космос Я пока не разобрался как оно работает и как так быстро, но оно летает.
Добавлено через 8 минут Usaga, я то не знаю на каких блоках оно будет тестироваться Постараюсь не использовать. На больших блоках не проверял, но на маленьких (10-1000 байт) получается что читающий поток наоборот ждет пока рабочие обработают блоки. В роли очереди использовал Queue. Постоянно возникает ощущение что я что-то делаю не так. Пока ковыряю примеры из вышеупомянутой темы. Последнее сообщение не совсем понял.
0
|
12073 / 8383 / 1280
Регистрация: 21.01.2016
Сообщений: 31,578
|
|
17.01.2017, 06:49 | 12 |
V0vchik, ты сам размер блока выбираешь. И зачем крайности такие? То 20Мб, то 1000 байт... Возьми пару мегабайт - этого должно быть более-менее достаточно.
Есть специализированный для многопоточности класс коллекции о котором я выше упомянал - BlockCollection. Ничего страшного. Со временем разберёшься. Но идея там проста: в программе есть только фиксированный набор блоков-контейнеров в которые данные с диска читаются. Эти блоки гоняются по кругу от читающего кода (Producer\Поставщик) к воркерам (Consumer\Потребитель) и назад к поставщику, когда работа над блоком окончена. Такой подход позволяет вообще избавиться от сборки мусора как таковой в этом процессе, ведь блоки с буферами переиспользуются, а не создаются каждый раз при каждой итерации чтения. И синхронизировать работу поставщика и воркеров проще: если все блоки заняты (пул пуст), то поставщик знает, что воркеры ещё не закончили работу и потому просто ждёт. Такую ситуацию легко можно будет увидеть в профилировщике и, соответственно, поигравщись размерами блоков\количеством потоков (воркеров) можно добиться оптимальной производительности.
0
|
12 / 12 / 13
Регистрация: 06.03.2011
Сообщений: 166
|
|
18.01.2017, 17:08 [ТС] | 13 |
Usaga, здравствуйте. Сегодня перековырял все свои решения и понял что проблема изначально была вот в этом методе: PrintByteArray. Заменил его на: BitConverter.ToString(hash).Replace("-",""); и все полетело. На обработку 100к блоков раньше уходило больше двух минут, а сейчас 10 секунд. Не понимаю как я раньше не понял этого
Добавлено через 1 минуту Usaga, а по поводу BlokingCollection я почитал о нем, но с ним не получиться. По условиям задания нельзя использовать ничего позже .net 3.5.
0
|
18.01.2017, 17:08 | |
18.01.2017, 17:08 | |
Помогаю со студенческими работами здесь
13
Последовательность байт файла, или определение сигнатуры в программе "Антивирус" Генерация сигнатуры файла, файл делится на блоки равной длинны Многопоточная генерация комбинаций Чтение полной сигнатуры файла - Си Написать консольную программу для генерации сигнатуры указанного файла (задействовать параллелизм) Генерация файла MP0B_001 Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |