Задачи против TPL Dataflow против Async / Await, что использовать, когда?

Я прочитал довольно много технических документов от некоторых из команды 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.


person Matt    schedule 27.11.2012    source источник
comment
«Каков вообще лучший подход?» Я думаю, что нет ни одного. Программирование часто сводится к рассмотрению альтернатив, и нет ни одной, которая явно была бы лучшей во всех случаях. Вот почему, когда вы заботитесь о производительности, вы должны использовать профилирование, нет «X всегда лучше, чем Y».   -  person svick    schedule 27.11.2012
comment
@svick, при всем уважении к вашему опыту и мнению, но именно поэтому я указал вариант использования и задал конкретные целевые вопросы, когда какой подход наиболее подходит. Не могли бы вы поделиться своими знаниями, как бы вы справились с каждым из 4 пунктов списка? Большое спасибо   -  person Matt    schedule 27.11.2012
comment
Не стесняйтесь закрывать его на Meta Stack Overflow.   -  person casperOne    schedule 27.11.2012
comment
@ Фредди Нет, потому что вы не согласны не в том месте. Это первый (из двух), на который вы указали Meta Stack Overflow. Комментарии предназначены для разъяснения вопроса. Они не предназначены для мета-комментариев (если вопрос будет открытым, закрытым и т. Д.).   -  person casperOne    schedule 02.12.2012


Ответы (1)


Похоже, у вас есть система «толкания». Простой async код обрабатывает только сценарии «вытягивания».

Вы можете выбрать между TPL Dataflow и Rx. Я думаю, что TPL Dataflow легче изучить, но, поскольку вы уже пробовали его, и он не сработает в вашей ситуации, я бы попробовал Rx.

Rx подходит к проблеме с совершенно другой точки зрения: он сосредоточен на «потоках событий», а не на «сетке акторов» TPL Dataflow. Последние версии Rx очень async дружественны, поэтому вы можете использовать async делегатов в нескольких точках вашего конвейера Rx.

Что касается дизайна вашего API, то и TPL Dataflow, и Rx предоставляют интерфейсы, которые вы должны реализовать: _4 _ / _ 5_ для TPL Dataflow и _6 _ / _ 7_ для Rx. Вы можете просто подключить реализации к конечным точкам вашей внутренней сетки (поток данных TPL) или запроса (Rx). Таким образом, ваши компоненты представляют собой просто «блок» или «наблюдаемый / наблюдатель / субъект», который может быть составлен из других «сеток» или «запросов».

Наконец, для вашей async системы конструирования вам просто нужно использовать фабричный паттерн. Ваша реализация может вызвать Task.Run для настройки потока пула потоков.

person Stephen Cleary    schedule 27.11.2012
comment
Когда вы предпочтете использовать систему push вместо простого написания методов, обрабатывающих данные после того, как методы async вернут результат? Я открыл вопрос здесь после прочтения нескольких ваших сообщений, в которых вы рекомендуете использовать поток данных, но я Я все еще не уверен, что полностью понимаю преимущества простого добавления метода процесса после ожидания асинхронных задач. Не могли бы вы уточнить или сослаться на образец, который я написал в этом вопросе? - person BornToCode; 31.07.2018
comment
Большинство систем по своей природе являются выталкивающими или вытягивающими и требуют перевода (фоновый процесс / буфер), если вы хотите использовать их по-другому. Например, получение записей из базы данных - это вытягивающая система; пользовательский ввод - это система push. Я предпочитаю использовать тот подход, который более естественен для данной ситуации; например, используйте async для запросов к базе данных и используйте events / Rx для ответа на ввод пользовательского интерфейса. - person Stephen Cleary; 01.08.2018