Мое приложение ожидает ввода от нескольких источников, например: графический интерфейс, файловая система мониторинга, голосовая команда, веб-запрос и т. Д.
Я сделал многоАсинхронное программирование в мое время.Я считаю полезным различать фоновые операции и асинхронные события .«Фоновая операция» - это то, что вы инициируете, и через некоторое время она завершается.«Асинхронное событие» - это то, что всегда происходит независимо от вашей программы;вы можете подписаться, получить события на некоторое время, а затем отказаться от подписки.
Таким образом, входы GUI и мониторинг файловой системы могут быть примерами асинхронных событий;тогда как веб-запросы являются фоновыми операциями.Фоновые операции также можно разделить на привязку к процессору (например, обработку некоторого ввода в конвейере) и привязку к вводу / выводу (например, веб-запрос).
Я делаю это различие, особенно в .NET, потому что разные подходыимеют разные сильные и слабые стороны.При выполнении ваших оценок вы также должны учитывать, как распространяются ошибки .
Во-первых, варианты, которые вы уже нашли:
ThreadPool.QueueUserWorkItem
- чуть ли не худший вариант.Он может обрабатывать только фоновые операции (без событий) и плохо обрабатывает операции ввода-вывода.Возвращать результаты и ошибки можно вручную. BackgroundWorker
(BGW) - не худшее, но определенно не лучшее.Он также обрабатывает только фоновые операции (без событий) и плохо обрабатывает операции ввода-вывода.Каждый BGW работает в своем собственном потоке - что плохо, потому что вы не можете воспользоваться преимуществом самобалансировки пула потоков.Кроме того, все уведомления о завершении (обычно) ставятся в очередь в один поток, что может стать причиной узкого места в очень загруженных системах. - Асинхронный шаблон на основе событий (EAP) - это первая опция из вашего списка, котораябудет поддерживать асинхронные события, а также фоновые операции, а также может эффективно обрабатывать операции ввода-вывода.Тем не менее, это довольно сложно для правильного программирования, и у него та же проблема, что и в BGW, когда уведомления о завершении (обычно) все ставятся в очередь в один поток.(Обратите внимание, что BGW - это EAP, применяемый к фоновым операциям, связанным с процессором).Я написал библиотеку , чтобы помочь в написании компонентов EAP, а также некоторых сокетов на основе EAP.Но я не рекомендую этот подход;в эти дни доступны лучшие варианты.
Tasks
в Task Parallel Library - Task
- лучший вариант для фоновых операций, как с привязкой к процессору, так и с вводом / выводом. Я просматриваю несколько вариантов фоновых операций в своем блоге - но эта запись в блоге вообще не затрагивает асинхронные события. - C # 5
async
/ await
- они позволяют более естественное выражениеиз Task
фоновых операций.Они также предлагают простой способ синхронизации обратно в контекст вызывающего, если вы хотите (полезно для операций, инициируемых пользовательским интерфейсом).
Из этих опций async
/ await
- самый простой дляиспользовать с Task
близкой секундой.Проблема с ними заключается в том, что они были предназначены для фоновых операций, а не для асинхронных событий.
Любой источник асинхронных событий может использоваться с использованием асинхронных операций (например, Task
), если у вас достаточно буфера для этих операций.События.Когда у вас есть буфер, вы можете просто перезапускать асинхронную операцию каждый раз, когда она завершается.Некоторые буферы предоставляются операционной системой (например, в сокетах есть буферы чтения, в окнах пользовательского интерфейса есть очереди сообщений и т. Д.), Но вам, возможно, придется самостоятельно предоставлять другие буферы.
Сказав это, вот мои рекомендации:
- Асинхронный шаблон на основе задач (TAP) - используя
await
/ async
или Task
напрямую, используйте TAP для моделирования по крайней мере ваших фоновых операций. - TPL Dataflow (часть VS Async ) - позволяет настроить «конвейеры» для данных, по которым они проходят. Поток данных основан на
Task
с. Недостатком Dataflow является то, что он все еще развивается и (IMO) не так стабилен, как остальная часть поддержки Async.
- Reactive Extensions (Rx) - это единственная опция, специально предназначенная для асинхронных событий, а не только для фоновых операций. Он официально выпущен (в отличие от VS Async и Dataflow), но кривая обучения круче.
Все три из этих параметров эффективны (используя пул потоков для любой фактической обработки), и все они имеют четко определенную семантику для обработки ошибок и результатов. Я рекомендую использовать TAP в максимально возможной степени; эти части могут быть легко интегрированы в Dataflow или Rx.
Вы упомянули «голосовые команды» в качестве одного из возможных источников ввода. Возможно, вас заинтересует видео BuildWindows , в котором поет Стивен Тауб - и использует поток данных для гармонизации своего голоса практически в реальном времени. (Стивен Тауб - один из гениев TPL, Dataflow и Async).