Если многократные события возникают (быстро), будет ли обработчик подписчика всегда вызываться в том порядке, в котором были вызваны события?
Нет.Во-первых, каждый вызов BeginInvoke ставит рабочий элемент в очередь потоков;каждый рабочий элемент выполняется в отдельном потоке, и эти потоки участвуют в гонке.Во-вторых, даже если ваши подписчики были вызваны в правильном порядке, эти вызовы все еще в гонке;и если вы берете блокировку внутри подписчика, порядок, в котором предоставляются блокировки, не определен.
Если я реализую блокировку в очереди, подобную упомянутой выше, могу ли я положиться на Enter () метод вызывается в правильном порядке?(т.е. все еще существует риск того, что «событие 2» достигнет queuedLock.Enter () в моем подписчике до «события 1», даже если «событие 2» сработало после «события 1»);
Нет, по тем же причинам, указанным выше.
Учитывая, что EventHandler должен быть асинхронным (чтобы подписчики не блокировали поток), это просто невозможно /разумно с EventHandler и мне нужно реализовать какую-то отдельную очередь асинхронных событий?
Да.Поскольку вы должны обрабатывать события по порядку, использование очереди предпочтительнее многопоточности.Нет смысла создавать несколько потоков только для того, чтобы заставить их всех ждать получения единой блокировки.
Использование очереди
При использовании очереди производитель только ставит в очередь событие без блокировки.На стороне потребителя есть один поток, который удаляет и обрабатывает события один за другим.Это поток, который вызывает подписчиков для каждого события.Обратите внимание, что потребительский поток будет заблокирован, пока очередь пуста.
Вы все равно можете распараллелить обработку
Например, если событие принадлежит (скажем, клиенту), а событияОт одного и того же Заказчика необходимо обрабатывать по порядку, тогда как два события от двух разных Заказчиков могут обрабатываться независимо
В этом случае вы можете разделить события, принадлежащие разным клиентам, на несколько очередей и иметь отдельный поток потребителей для каждой очереди.Чтобы это работало, вы должны убедиться, что события от одного и того же клиента отображаются в одну и ту же очередь.
Например, если у вас есть N очередей, вы можете отобразить событие в очередь, вычислив хэш (Customer) по модулю N.
Существующие очереди производителя-потребителя
.NET предоставляет несколько специализированных очередей, из коробки:
Вы также можете взглянуть на:
- TPL DataFlow , который предоставляет более производительные альтернативы.
- LMAX Disruptor , если вам нужен сверхэффективный бэкэнд.