Ответ 1
async
сам по себе довольно совершенен. В этом много работы.
В общем, на стороне сервера вас беспокоит async
I/O. Я проигнорирую async
методы с привязкой к ЦП, потому что накладные расходы async
все равно будут потеряны.
Асинхронный ввод-вывод увеличит использование вашей памяти в каждом запросе, но это уменьшит потребление потоков для каждого запроса. Таким образом, вы в конечном итоге выигрываете (кроме пограничных патологических угловых случаев). Это справедливо для всех асинхронных операций ввода-вывода, включая async
.
await
был разработан с шаблоном, а не только с типом Task
, поэтому, если вам нужно выжать как можно больше производительности, вы можете.
Я прочитал статью о влиянии производительности на эти приложения, поскольку компилятор будет генерировать довольно сложный конечный автомат для методов async.
статья, которую вы прочитали Стивеном Тубом, превосходна. Я также рекомендую Zen Async video (также Стивен Туб).
Асинхронное программирование с использованием этих ключевых слов намного проще, но так же хорошо, как сказать SocketAsyncEventArgs для сокетов?
Во-первых, поймите, что SocketAsyncEventArgs
является более масштабируемым, поскольку он уменьшает количество мусора. Более простой способ использования сокетов async
будет генерировать больше мусора памяти, но поскольку await
основан на шаблонах, вы можете определить свои собственные async
-компьютерные обертки для API SocketAsyncEventArgs
(как видно на блоге Стивена Тууба... Я чувствую шаблон здесь;). Это позволяет вам выжимать каждую унцию производительности.
Хотя в конечном итоге обычно лучше разрабатывать масштабируемую систему, а не скручивать код, чтобы избежать небольшого выделения памяти. ИМХО.
Второй вопрос: являются ли асинхронные методы ввода-вывода, такие как Stream.WriteAsync, действительно асинхронными (Completion Ports on.NET или epoll/poll на Mono), или эти методы являются дешевыми оболочками для нажатия вызова записи в threadpool?
Я не знаю о Моно. В .NET большинство асинхронных методов ввода-вывода основаны на порте завершения. Класс Stream
является заметным исключением. Базовый класс Stream
по умолчанию будет делать "дешевую упаковку", но позволяет производным классам переопределять это поведение. Stream
, которые поступают из сетевых коммуникаций, всегда переопределяют это, чтобы обеспечить действительно асинхронный ввод-вывод. Stream
, которые обрабатывают файлы только для переопределения этого , если, поток был сконструирован явно для асинхронного ввода-вывода.
Третий вопрос: помимо SynchronizationContext приложения UI существует ли способ реализовать какой-то однопоточный контекст?
ASP.NET также имеет SynchronizationContext
, поэтому, если вы используете ASP.NET, вы уже настроены.
Если вы выполняете собственный сервер на основе сокетов (например, службу Win32), вы можете использовать тип AsyncContext
в моей библиотеке AsyncEx. Но это звучит не так, как хотелось бы. AsyncContext
создаст однопоточный контекст для текущего потока. Но истинная мощность async
для серверных приложений исходит из запросов масштабирования вместо потоков.
Рассмотрим, как работает ASP.NET SynchronizationContext
: по мере поступления каждого запроса он захватывает поток пула потоков и строит SynchronizationContext
(для этого запроса). Когда этот запрос выполняет асинхронную работу, он регистрируется с помощью SynchronizationContext
, а поток, выполняющий этот запрос, возвращается в пул потоков. Позже, когда асинхронная работа завершается, она захватывает поток пула потоков (любой поток), устанавливает на нем существующий SynchronizationContext
и продолжает обрабатывать этот запрос. Когда запрос завершен, его SynchronizationContext
размещается.
Ключом в этом процессе является то, что когда ожидание запроса (await
) асинхронных операций, нет потоков, посвященных этому запросу. Поскольку запрос значительно облегчен по сравнению с потоком, это позволяет серверу масштабироваться лучше.
Если вы предоставили каждому из ваших запросов однопоточное SynchronizationContext
, например AsyncContext
, это привязало бы поток к каждому запросу, даже если ему нечего делать. Это вряд ли лучше, чем синхронный многопоточный сервер.
Вы можете найти мою статью async voidи await
, поэтому вам не придется делать это явно.