Я прочитал довольно много технических документов от некоторых из команды Microsoft или других авторов, подробно описывающих функциональность новой библиотеки TPL Dataflow, фреймворков async / await для параллелизма и TPL. Тем не менее, я не встречал ничего, что бы четко определяло, что и когда использовать. Я знаю, что у каждого есть свое место и применимость, но меня особенно интересует следующая ситуация:
У меня есть модель потока данных, которая работает полностью внутри процесса. Вверху находится компонент генерации данных (A), который генерирует данные и передает их либо через связи блоков потока данных, либо через создание событий в компонент обработки (B). Некоторые части внутри (B) должны выполняться синхронно, в то время как (A) значительно выигрывает от параллелизма, поскольку большинство процессов связаны с вводом-выводом или процессором (чтение двоичных данных с диска, затем их десериализация и сортировка). В конце компонент обработки (B) передает преобразованные результаты в (C) для дальнейшего использования.
Мне особенно интересно, когда использовать блоки потока данных task, async / await и TPL в отношении следующего:
Запускаем компонент генерации данных (A). Я явно не хочу блокировать графический интерфейс / панель инструментов, поэтому этот процесс должен в некоторой степени выполняться в другом потоке / задаче.
Как вызвать методы в (A), (B) и (C), которые не участвуют напрямую в процессе генерации и обработки данных, но выполняют работу по настройке, возврат которой может занять несколько сотен миллисекунд / секунд. Я догадываюсь, что именно здесь сияет async / await?
Больше всего я борюсь с тем, как лучше всего спроектировать передачу сообщения от одного компонента к другому. TPL Dataflow выглядит очень интересно, но иногда он слишком медленный для моей цели. (Обратите внимание на проблемы с производительностью в конце). Если не использовать TPL Dataflow, как мне добиться оперативности и параллелизма за счет внутрипроцессной межзадачной / параллельной передачи данных? Пример: очевидно, что если я инициирую событие в задаче, подписанный обработчик событий запускается в той же задаче, а не передается другой задаче, верно? Таким образом, как компонент (A) может продолжать свою деятельность после передачи данных компоненту (B), в то время как компонент (B) извлекает данные и сосредотачивается на их обработке? Какую модель параллелизма лучше всего использовать здесь? Я реализовал здесь блоки потока данных, но действительно ли это лучший подход?
Я полагаю, что приведенные выше пункты вкратце указывают на мою борьбу с тем, как проектировать и внедрять компоненты типа API, используя стандартную практику? Следует ли разрабатывать методы асинхронно, вводить данные как блоки потока данных, а вывод данных как блок потока данных или как событие? Какой вообще лучший подход? Я спрашиваю, потому что большинство компонентов, упомянутых выше, должны работать независимо, поэтому они могут быть заменены или независимо изменены внутри без необходимости перезаписывать средства доступа и вывод.
Примечание по производительности. Я упомянул, что блоки потока данных TPL иногда бывают медленными. Я имею дело с приложениями с высокой пропускной способностью, низкой задержкой и ограничениями ввода-вывода целевого диска, и поэтому блоки потока данных tpl часто выполняются намного медленнее, чем, например, блок синхронной обработки. Проблема в том, что я не знаю, как встроить процесс в его собственную задачу или параллельную модель, чтобы добиться чего-то похожего на то, о чем уже позаботились блоки потока данных tpl, но без накладных расходов, связанных с tpl df.