Как лучше написать класс управления сохранением данных во множество файлов?
Всех приветствую.
Решаю следующую задачу: Необходимо написать класс, принимающий данные от множества клиентов и самостоятельно сериализующий данные в соответствующие файлы. Данные - описанные в проекте структуры либо классы.
Также, по запросу от клиента класс возвращает десерилизованные данные из файла.
Всё общение производится через механизм событий.
Я разобрался со всем, кроме работы с потоками. Так как никогда раньше не работал с ними, то погрузился в статьи и откровенно говоря запутался. Обилие вариантов, описанных в мсдн внушает)
Потому прошу вас помочь советами и указать где я ошибся в рассуждениях.
1) Итак, класс не должен прекращать свою работу и должен продолжить принимать сигналы. но нельзя записывать или считывать данные из файлы, который сейчас занят другим потоком. У меня есть список файлов, достаточно ли мне добавить к каждому из них флажок занят/не занят, чтобы потоки проверяли его наличие и ждали некоторое время до новой попытки записи? Или есть более продвинутые и гибкие подходы?
2) События происходят часто. Поэтому постоянно создавать и убивать потоки бессмысленно - производительность упадет в разы из-за постоянной смены контекста. Однако процесс записи и чтения в файл может занимать продолжительное время. Напрашивается использовать async/await - один поток для одного файла. Причем после выполнения задачи, поток должен ждать новых данных. Вопросы:
а_0) А асинхронность мне тут вообще нужна? Не добьюсь ли я тех же результатов, имея отдельные параллельные потоки?
а) Насколько грамотно дать каждому потоку очередь входных данных, чтобы при поступлении новых данных тот забирал их и сохранял в файл? А остальное время в бесконечно цикле опрашивает очередь на наличие элементов.
Мне нравится это вариант тем, что однажды созданный поток будет работать не вмешиваясь в основной + взаимодействие потоков ограничивается лишь совместным доступом к очереди. Где я не прав?
б) Второй вариант имеет иную логику. Каждый поток выполняет задачу и потом встает в режим ожидания. Основной поток получает данные по ивентам, складирует их в очередь и дожидается когда нужный поток освободится. Затем когда нужный поток освободился, вызывает его и передает аргументы - массив данных.
Упростит ли это работу и что лучше по производительности?
в) Доработка варианта Б - вместо прямого вызова потока и передачи ему данных используется событие. Чем этот вариант лучше/хуже других?
Остальные вопросы:
3) Можно ли хранить список асинхронных потоков? если да, то как?
4) Как асинхронный поток поставить на ожидание?
Мне по душе вариант а. Потокобезопасная очередь это не миф, вполне реальная задача. Единственное что я бы добавил - раз файлы могут обрабатываться долго, то я бы добавил туда еще 1-2 потока. Пусть разбирают если один занят. Мне только не очень понятно что делать если файлы разные, но имеют одинаковое имя( 1.jpg например). Получает ли клиент идентификатор файла по которому его потом забрать или по фазам луны придется догадаться какой файл ему нужен.
Остальные вопросы:
3) Можно ли хранить список асинхронных потоков? если да, то как?
4) Как асинхронный поток поставить на ожидание?
3. Можно. Thread Pool.
4. Thread.Sleep(2000) или await Task.Delay(2000). Но лучше вернуть его системе, пускай на нем что-нибудь умное сделает.
Если просто - Plinq. Он немного знает о системе (что именно у вас есть) и не будет запускать больше потоков чем нужно. Так же может не параллелить вообще.
При большом количестве работы медленней кучи Task. Но куча таск отъест кучу памяти и будет секунд 20 аллокировать треды.
Зато просто. Пишете простую итерацию на linq и потом добавляете пару букв.