Мое приложение ожидает входные сигналы от нескольких источников, например: графический интерфейс пользователя, контроль файловую систему, голосовые команды, веб-запрос и т.д.
я сделал целый много асинхронного программирования в мое время. Мне полезно различать фоновые операции и асинхронные события. «Фоновая операция» - это то, что вы инициируете, и через некоторое время оно завершается. «Асинхронное событие» - это то, что всегда происходит независимо от вашей программы; вы можете подписаться, получить события на время, а затем отказаться от подписки.
Таким образом, входы графического интерфейса и мониторинг файловой системы являются примерами асинхронных событий; тогда как веб-запросы представляют собой фоновые операции. Фоновые операции также можно разделить на привязку к ЦП (например, обработку некоторого ввода в конвейере) и привязку ввода/вывода (например, веб-запрос).
Я делаю это различие особенно в .NET, потому что разные подходы имеют разные сильные и слабые стороны. При проведении оценок вы также должны учитывать, как ошибки распространяются.
Во-первых, варианты, которые Вы уже нашли:
ThreadPool.QueueUserWorkItem
- почти самый худший вариант вокруг. Он может обрабатывать только фоновые операции (без событий) и не обрабатывает операции с привязкой к I/O. Возвращаемые результаты и ошибки являются как ручными.
BackgroundWorker
(BGW) - не самое худшее, но определенно не лучшее. Он также обрабатывает только фоновые операции (без событий) и не обрабатывает операции с привязкой к I/O. Каждый BGW работает в своем собственном потоке - что плохо, потому что вы не можете воспользоваться преимуществами самозанятости работы пула потоков. Кроме того, уведомления о завершении (обычно) помещаются в очередь на один поток, что может вызвать узкое место в очень загруженных системах.
- Асинхронный шаблон на основе событий (EAP) - это первый вариант из вашего списка, который будет поддерживать асинхронные события, а также фоновые операции, а также может эффективно обрабатывать операции с привязкой к вводу/выводу. Тем не менее, некорректно запрограммировать программу, и она имеет ту же проблему, что и BGW, где уведомления о завершении (обычно) помещаются в один поток. (Обратите внимание, что BGW - это EAP, применяемый к фоновым операциям с привязкой к процессору). Я написал a library, чтобы помочь в написании компонентов EAP вместе с некоторыми сокетами на основе EAP. Но я не рекомендую этот подход; в наши дни есть лучшие варианты.
Tasks
в параллельной библиотеке задач - Task
- лучший вариант для фоновых операций, как связанных с ЦП, так и привязки ввода-вывода. I review several background operation options on my blog - но это сообщение в блоге не затрагивает асинхронные события вообще.
- C# 5
async
/await
- Они позволяют более естественное выражение фоновых операций Task
. Они также предлагают простой способ синхронизации с контекстом вызывающего, если вы хотите (полезно для операций, инициированных UI).
Из этих вариантов async
/await
является самым простым в использовании, с Task
близкими вторым. Проблема заключается в том, что они были предназначены для фоновых операций, а не для асинхронных событий.
Любой источник асинхронного события может потребляться с использованием асинхронных операций (например, Task
), если у вас есть достаточный буфер для этих событий. Когда у вас есть буфер, вы можете просто перезапустить асинхронную операцию каждый раз, когда она завершается. Некоторые буферы предоставляются ОС (например, сокеты имеют буферы чтения, окна пользовательского интерфейса имеют очереди сообщений и т. Д.), Но вам, возможно, придется предоставлять другие буферы.
Сказав, что, вот мои рекомендации:
- Task-based Asynchronous Pattern (TAP) - с использованием либо
await
/async
или Task
непосредственно, использование ТАР для моделирования, по меньшей мере фоновые операции.
- TPL Dataflow (часть VS Async) - позволяет вам создавать «трубопроводы» для передачи данных. Поток данных основан на
Task
с. Недостатком Dataflow является то, что он все еще развивается и (IMO) не так стабилен, как остальная поддержка Async.
- Reactive Extensions (Rx) - это единственный вариант, специально предназначенный для асинхронных событий, а не только для фоновых операций. Он официально выпущен (в отличие от VS Async и Dataflow), но кривая обучения более крутая.
Все три из этих вариантов являются эффективными (с использованием пула потоков для любой реальной обработки), и все они имеют четко определенную семантику для обработки ошибок и результатов. Я рекомендую использовать TAP как можно больше; эти части затем могут быть легко интегрированы в Dataflow или Rx.
Вы упомянули «голосовые команды» как один из возможных источников входного сигнала. Вас может заинтересовать BuildWindows video, где поёт Стивен Туб, и использует Dataflow для гармонизации своего голоса в почти реальном времени. (Стивен Туб - один из гениев за TPL, Dataflow и Async).
Видеоролик BuildWindows, как правило, очень воспитывает. Благодаря! – m0s