C#でTCPサーバを実装するにはいくつか方法があります。
まずTCPサーバの実装方法毎の比較をし、その中でも記述量とパフォーマンスのバランスに優れたasync修飾子の使い方を紹介をします。
実装方法の比較1
|実装方法 |行数|難易度|秒間リクエスト数|
|-------------|-------|-------|-------|-------|
|async/await |101|易しい|56,916|
|非同期ソケット|170|難しい|68,272|
|ThreadPool |98|易しい|51,129|
速度を求めるなら非同期ソケット、開発のし易さならasync修飾子という使い分けが良さそうな結果です。
という訳でasyncについて使い方などを見ていきます
async修飾子を使うと非同期処理が簡単
以下のコードは1秒間処理を遅延させるTask.Delay(1000)を合計100回実行していますが、処理は1秒足らずで終了し、計算結果も正しく表示されます。 2
従来でも ThreadPool.QueueUserWorkItem などを使えば時間のかかる処理をバックグラウンドに回すことは出来ましたが、この例の様に100個の非同期処理を「待ち合わせる」というのはここまで簡単には書けませんでした。
using System;
using System.Linq;
using System.Threading.Tasks;
class Program
{
public static void Main()
{
var tasks = Enumerable.Range(1, 100).Select(run).ToArray();
Task.WaitAll(tasks);
Console.WriteLine(tasks.Sum(x => x.Result));
}
static async Task<int> run(int n)
{
await timeConsumingWork().ConfigureAwait(false);
return n * 2;
}
static Task timeConsumingWork()
{
return Task.Delay(1000);
}
}
非同期ソケットがやっと扱いやすくなった
非同期ソケットは170行も実装に使っていますが、async/awaitは101行とコンパクトにまとまってます。
また、try/catchの範囲も非同期ソケットはコールバック関数を使っているため一括りに例外を補足できないのに対して、async/awaitの方はいつも通りの記述ができています。
という訳でasync/awaitオススメです
直感的に書けて読めるのでC#の非同期通信はasync修飾子をゴリゴリ使って書くのがよさそうです。パフォーマンスも悪くありませんし。