OS: Pop!_OS 22.04 LTS
dotnet: 8.0.204
という環境で、
ASP.NET coreのWEBアプリケーションから、
mysql, memcached, redisへのアクセスをするのベンチマークをしてみたところ、
同期>非同期
となる局面があったので、書いておきます。
使用したライブラリは、
mysql: https://github.com/mysql-net/MySqlConnector
memcached: https://github.com/cnblogs/EnyimMemcachedCore
redis: https://github.com/StackExchange/StackExchange.Redis
です。
行ったベンチマークは、1回のリクエスト〜レスポンス処理の間に、上記データベースに複数回問い合わせるというもので、
よくあるWEBアプリケーションみたいな感じのものです。
で、結果を載せるほうがよいのですが、環境によって大きく左右されるので、
「こういうときは同期が速い」という所感レベルなものとさせていただきます。
というか、なんでこんなことをしたのかというと、
C#界隈では、どうしてもasync/awaitを使った非同期がベストプラクティスと言われているのですが、
async/awaitを使った非同期って、
・await一箇所でも書かなかったら実行時に気づかないような不具合を生むことがあり、
大きいプロジェクトほど、そのミスに気づけなくなる。
・呼び出し階層がすべて非同期になっている必要がある。
・ローカルネットワーク内にあるmysqlのような高速なデータベースに、
主キーで問い合わせるなどの高速なIOのケースにおいて、
CPUのコンテキストスイッチのほうがコスト高いときがあるんじゃないか?という疑問をもっていた。
のような課題もあるなとずっと思っていました。
とはいえ、同期の欠点は「詰まりやすい」ということで、
確かに1つの処理が遅れると、全体の遅れに影響してくるというのも経験しています。
しかしながら、エンドレスにハイトラフィックな事例というのもごく一部であり、
アプリケーションサーバのCPUを常に100%近く使うようにさせられている(つまり無駄を削ぎ落とす)
ようなことも稀かと思います。
ITの世界では、大は小を兼ねるかと思いますが、予算も限られた中でやるとして、
一定の余裕がある構成で、トラフィックも読めているのであれば、
無理にすべてをasync/awaitの非同期でやる必要もないとは個人的には考えています。
とはいいつつも、昨今のデータベースなどのミドルウェア事情として、ITの巨人が開発した巨大なソフトウェアを利用する局面も増えており、
こういったものは、mysqlのスタンドアロンとは違い、内部的になんども通信しているため、
IOレイテンシーは悪くなっています。
となると、結局、こういったものを利用することを想定して、
IOレイテンシーが悪くなっても耐えうるアプリケーションを用意しておかないといけないなと思いったわけです。
だけど、やっぱり計測してみないといけないなと思い、同期と非同期のベンチマークを取ったということです。
話が少しそれましたが、
同期>非同期
となるのは、
・同一ネットワーク内で高速なIOが見込めるとき
・アプリケーションに負荷がかかっていないとき
という条件を同時に満たすときです。
これが満たせなければ非同期のほうが良いと思われます。
たとえば、
・インターネット越しにIOを行う
・IOが高速でないデータベースを使う
・アプリケーションへの負荷が高いことが予想される
などの場合は、非同期に分があるでしょう。
C#のASP.NETでkerstrelを使う場合、スピンアップの悪さも、
非同期を使うことで抑え込めるという利点もあります。
「結局非同期のほうがいいじゃないか」という結論とも捉えられますが、
いろいろ考えると「結局非同期のほうがいい」のです。
ただ、1回でもawait書き忘れた場合のリスクについては、
開発エンジニアへの教育であったり、レビューなどでカバーしないといけないか思います。
私は、C#を利用している側の人間に過ぎないのですが、
こういったリスクについても、ふっとばされているようにも感じます。
「当たり前」なのかもしれませんが、開発エンジニアの知識レベルは様々であり、
ただでさえ近年複雑な要求仕様に対応を迫らている上で、
完璧な非同期コードを書くことも一苦労だと思います。
なので、非同期のリスク(お作法)についても、現場の理解力と、教育が大事だなと思う今日この頃です。
駄文失礼いたしました。
以上