C# - async/await 非同期サーバー実装メモ

ASP.NET CoreのドキュメントにKestrel(Webサーバー)ドキュメントにマネージドソケットに基づくと書いてあり、
どうしているのか気になったので簡単に確認してみた。(そして、わりと速いらしい)

コードはGithub
ASP.NET Core の作法として、Kestrel ServerのStartAsyncが多分呼ばれる。
各種BindAsyncConfigureAwait(false)として経由して、SocketTransportへ到達する。
SocketTransportにて、リッスン用のソケット(Socket)生成、BindListenを行い、そのリッスンソケットを使ってTask.Run()内でAcceptループを回している。
Acceptは await AcceptAsync()で待ち、接続あったら両方向のPipelines.Pipeを生成して、送受信処理をそれぞれawaitで待つ。完了したらDispose
ソケット送受信処理ではTask(ValueTask)を返す拡張メソッドを使用せずSocketAsyncEventArgsという(たぶん古い非同期プログラミングモデル用)のを拡張して使っている。こっちのほうが速いのか?
後、データ受け渡しがMemory<>とかReadOnlySequence<>になってるね。

ということで、とりあえず
Socket直接触る(TCPxxx, UDPxxxでやらない)、AcceptAsync/SendAsync/ReceiveAsync(/ConnectAsyncも) をawaitする、データのやり取りはPipelinesとかMemoryで
をしておけばよいのかな。
ASP.NET Core Generic Hostに dotnettyみたいなのが乗ってくれると良いのかもしれない。

追記

2019-02-27

Socketの非同期実装についてdotnet/corefx | GitHubの中を覗いてみたら、Unix(Linux/macOS)のときは下(ネイティブ実装)のほうでepoll/kqueue使ってイベント監視していた。
だからawaitしておけば、いい感じにI/Oイベント拾ってスレッドが割り当てられて、それなりに動く。ということでいいのか。
フレームワークも色々あるようなので、直接触らないず済ませるくらいで丁度よいかもしれない。


See also