LoginSignup
58
59

More than 5 years have passed since last update.

C#で高速なTCPサーバを実装するためのasync/await入門

Posted at

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修飾子をゴリゴリ使って書くのがよさそうです。パフォーマンスも悪くありませんし。


  1. ThreadPoolはThreadPool.SetMinThreads()でworkerスレッドを同時接続数と同等程度に設定しないと上記の性能が出ませんでした。また検証に使ったコードをgithubに置いています。 

  2. wandboxでコードを実行 

58
59
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
58
59