Многопоточность и архитектура. Объясните простые вещи.
От:
Аноним
Дата:
17.06.11 05:20
Оценка:
Здравствуйте,
Нужно проверить все файлы на диске. Создаем несколько типов задач для этого: обход директории, чтение файла, проверка.
Самое длительное — обход директории, выполняется в одном потоке, собирает файлы. Далее читаем и проверяем полученные файлы в несколько потоков.
Так вот объясните самым понятным языком, как реализовать управление такими задачами.
Непонятно вот что:
извне может поступить сигнал — паузка, остановка, продолжение.
Как это реализовать просто и расширяемо? Как работает SetEvent? Мы его создаем CreateEvent, и ждем WaitForSingleObject. Когда нужно выполнить задачу в пуле,
делаем SetEvent, что происходит в этот момент??
Почему во всех реализациях пулов потоков, нет простых операций: Pause, Resume, Stop, OnTaskStart, OnTaskEnd?
Мне нужно максимально простое решение с точки зрения архитектуры. Чтобы допустим, при добавлении задачи: "загрузка сигнатур", это не затрагивало задачу "проверка файла".
Спасибо.
Re: Многопоточность и архитектура. Объясните простые вещи.
А>Почему во всех реализациях пулов потоков, нет простых операций: Pause, Resume, Stop, OnTaskStart, OnTaskEnd?
Потому что пул потоков — это низкоуровнивый примитив. Не такой низкоуровнивый как "поток" или "объект синхронизации типа event", но примитив. Сам по себе он, увы, ничего не может. То что вы хотите — это уже "движок программы". Который пишется с использованием примитивов. Можно с помощью пула потоков, можно с помощью просто потоков и примитивов синхронизации. А уж у самого движка есть и Pause, и Resume, и OnTaskStart, и аже onTaskEnd. Как раз недавно такой писал . Написать такой движок не очень сложно, в зависимости от используемых библиотек это 50-500 строк. Я на Qt где-то в 100 уложился.
А>Как это реализовать просто и расширяемо? Как работает SetEvent? Мы его создаем CreateEvent, и ждем WaitForSingleObject. Когда нужно выполнить задачу в пуле, А>делаем SetEvent, что происходит в этот момент??
Ну это как бы надо почитать документацию по используемому вами языку и фреймворку. Вы же не надеетесь, что вам тут зачитают лекцию по языку программирования, его библиотекам и по мультипоточному программированию? . Если есть конкретные вопросы — обращайтесь.
А>Мне нужно максимально простое решение с точки зрения архитектуры. Чтобы допустим, при добавлении задачи: "загрузка сигнатур", это не затрагивало задачу "проверка файла".
Поток обхода дерева файлов их обходит. Для каждого найденного файла он передает его путь объект — "аккумулятор задач". N потоков-обработчиков в цикле обращаются к аккумулятору задач с запросом "дай задачу". Аккумулятор задач на запрос "дай задачу" отдает путь к файлу и что с ним надо делать — сигнатуры там читать или что. Соответственно пауза реализуется через команду аккумулятору задач "пока больше задач не давать". Ну и можно еще поток обхода файловой системы на паузу поставить, чтобы диском не вертел.
Это одно из примитивнейших решений "в лоб". В зависимости от требований можно и пул потоков прикрутить, и по другому сделать.
Re: Многопоточность и архитектура. Объясните простые вещи.
я не думаю что дисковые операции станут быстрее если их делать из нескольких потоков. скорее всего медленней.
единственная задача которую можно распараллелить это проверка файлов. да и сначала лучше сделать в одном потоке все.
Re[2]: Многопоточность и архитектура. Объясните простые вещи
От:
Аноним
Дата:
17.06.11 07:52
Оценка:
Здравствуйте, __kot2, Вы писали:
__>я не думаю что дисковые операции станут быстрее если их делать из нескольких потоков. скорее всего медленней. __>единственная задача которую можно распараллелить это проверка файлов. да и сначала лучше сделать в одном потоке все.
Распараллеливать собирался на этапе чтения файлов. Ну думаю и это, в тот же поток правильней будет, чтобы диск не мучать.
Суть, что еще к "читателям" прибавиться чтение, куки, реестра, памяти. => Делаем один пул для читателей и один для сканеров.
Есть еще пересекающиеся задачи — загрузка сигнатур. Их видимо в отдельный пул загрузчиков.
Итого, как весь этот зоопарк сделать гибким при этом потоко-безопасным, и простым?? Поглядел в сторону аспектно-ориентированного, пока ничего не понял...
Вроде такого:
Имеем три типа задач, 2 рид онли — чтение,сканирование, 1 — загрузчики сигнатур. =>3 пула потоков. Уже упростили. Теперь остался вопрос,
взаимодействия — сканер<->данные. Локеры, multi-reader single-writer — хорошо. Как это с точки зрения АОП может выглядеть?? Чистый С++ и WinApi.
Re[3]: Многопоточность и архитектура. Объясните простые вещи
Здравствуйте, Аноним, Вы писали: А>Распараллеливать собирался на этапе чтения файлов. Ну думаю и это, в тот же поток правильней будет, чтобы диск не мучать. А>Суть, что еще к "читателям" прибавиться чтение, куки, реестра, памяти. => Делаем один пул для читателей и один для сканеров.
ой, навороты какие-то. не надо никаких читателей. все пусть в одном потоке делается. попробуйте просто копирование параллельно двух разных файлов запустить с диска — он как трещотка трещать начнет все время головку перепозицинирую и тормозить будет страшно.
А>Есть еще пересекающиеся задачи — загрузка сигнатур. Их видимо в отдельный пул загрузчиков.
трещотка будет
А>Итого, как весь этот зоопарк сделать гибким при этом потоко-безопасным, и простым?? Поглядел в сторону аспектно-ориентированного, пока ничего не понял... А>Вроде такого: А>Имеем три типа задач, 2 рид онли — чтение,сканирование, 1 — загрузчики сигнатур. =>3 пула потоков. Уже упростили. Теперь остался вопрос,
какое аспекто-отриентированное? зачем задачи? зачем загрузчики? зачем столько гемора? задача элементарно в лоб делается. распараллеливать смысл имеет только проверки.
Re[2]: Многопоточность и архитектура. Объясните простые вещи
От:
Аноним
Дата:
17.06.11 08:12
Оценка:
Здравствуйте, Eye of Hell, Вы писали:
А>>Почему во всех реализациях пулов потоков, нет простых операций: Pause, Resume, Stop, OnTaskStart, OnTaskEnd?
EOH>Потому что пул потоков — это низкоуровнивый примитив. Не такой низкоуровнивый как "поток" или "объект синхронизации типа event", но примитив. Сам по себе он, увы, ничего не может. То что вы хотите — это уже "движок программы". Который пишется с использованием примитивов. Можно с помощью пула потоков, можно с помощью просто потоков и примитивов синхронизации. А уж у самого движка есть и Pause, и Resume, и OnTaskStart, и аже onTaskEnd. Как раз недавно такой писал . Написать такой движок не очень сложно, в зависимости от используемых библиотек это 50-500 строк. Я на Qt где-то в 100 уложился.
Так все же, как по вашему организовать поступление событий Pause, Resume? Просто сохранить состояние потока и данных при паузе, и восстанавливать при продолжение.
Ну если не мудрить, то просто Suspend(CurrentThread) внутри объекта задачи?? Я до конца не понимаю, что происходит при прерывании потока например посреди выполнения функции..
А>>Как это реализовать просто и расширяемо? Как работает SetEvent? Мы его создаем CreateEvent, и ждем WaitForSingleObject. Когда нужно выполнить задачу в пуле, А>>делаем SetEvent, что происходит в этот момент??
EOH>Ну это как бы надо почитать документацию по используемому вами языку и фреймворку. Вы же не надеетесь, что вам тут зачитают лекцию по языку программирования, его библиотекам и по мультипоточному программированию? . Если есть конкретные вопросы — обращайтесь.
С++ и WinApi. Подумываю прикрутить boost, ради реализации threadpool, но по мне так избыточно. От того и столько вопросов. в буст реализации только 2 операции "добавить в очередь" и "ждать-пока", впрочем как и в .NeT. Ну
там колбэки еще. Мне нужно знать момент завершения задачи, чтобы перенаправить данные другому пулу.
А>>Мне нужно максимально простое решение с точки зрения архитектуры. Чтобы допустим, при добавлении задачи: "загрузка сигнатур", это не затрагивало задачу "проверка файла".
EOH>Поток обхода дерева файлов их обходит. Для каждого найденного файла он передает его путь объект — "аккумулятор задач". N потоков-обработчиков в цикле обращаются к аккумулятору задач с запросом "дай задачу". Аккумулятор задач на запрос "дай задачу" отдает путь к файлу и что с ним надо делать — сигнатуры там читать или что. Соответственно пауза реализуется через команду аккумулятору задач "пока больше задач не давать". Ну и можно еще поток обхода файловой системы на паузу поставить, чтобы диском не вертел.
EOH>Это одно из примитивнейших решений "в лоб". В зависимости от требований можно и пул потоков прикрутить, и по другому сделать.
Пока только перебираю варианты. Цель — сделать архитектуру сканера максимально просто. Чтобы завершение одной задачи — порождало другую. Суть чтение->анализ. 2 разных пула+Данные.
Re[3]: Многопоточность и архитектура. Объясните простые вещи
А>Так все же, как по вашему организовать поступление событий Pause, Resume? Просто сохранить состояние потока и данных при паузе, и восстанавливать при продолжение. А>Ну если не мудрить, то просто Suspend(CurrentThread) внутри объекта задачи?? Я до конца не понимаю, что происходит при прерывании потока например посреди выполнения функции..
Способов много. Делать суспенд потокам — не очень хорошая идея, это сильно аппаратно зависимо. Гораздо проще сделать паузу у двух объектов — того, который выдает задачи и который аккумулирует результаты. Ставим их оба на паузу (первый перестает задачи выдавать, второй перестает отдавать результаты) и у нас есть пауза. А то, что какой-то поток в это время читал из файла, успешно считает и что-то сделает — нам не критично, потому что результат он передаст объекту, собирающему результаты, а тот — на паузе и никуда дальше результат не отдаст пока с паузы не снимут.
Re[3]: Многопоточность и архитектура. Объясните простые вещи
Посмотрите, как сделано в .NET 4 Parallel Extensions (если пишите под .net, то просто используйте их). Там как раз есть таски, есть выстраивание их в цепочку, есть джойны тасков, есть механизм отмены, контроль количества потоков (вот эту пачку тасков делаем в 1 поток, а вот эту — в 5. При этом используется один пул) и даже визуальный отладчик