C#:Webの非同期処理【async-await】

C# Web

今回は非同期処理の中でも、Webの非同期処理について見ていきたいと思います。

例えば、『ボタンを押されて5秒間重たい処理が走っている間、反応しない』のは同期処理です。逆に、何かしら反応してくれるのが非同期処理による実装になります。
しかしながら、Webにその考えを持ち込んでしまうと、プチパニックになります。なぜならWebの場合は目的が違うからです。

スポンサードサーチ

Webの場合は、資源を有効に使うため

Webの場合の非同期処理にする利点は、資源を有効に使うためです。
IISの場合だと、100本の同時のリクエストに応答することができ、これは、すなわち100本分のスレッド(処理できるライン)があるということを意味します。

その為、非同期処理の説明でよくある『メインスレッド』がどうというのは少々訳が違います。
このような場合は、クライアントアプリで、表示部分も実装しなければならない時に出てくる話です。

しかしながらWebの場合は表示部分に関しては、天下のブラウザ様が行ってくれるため、画面が止まってしまうという事は考えなくても良いわけです。つまり非同期処理は必須ではないのです。
しかし、非同期処理を正しく設定することで、スレッド(資源)を有効活用することができます。
ではまずは、実際にどのように書いていくのか見てみましょう

ともかく書いてみよう

といっても私もプロじゃなく、とりあえずこれだけ覚えておけばOKという書き方しか知りません。

  • とりあえずasyncと書く
  • とりあえずTask < 型名 >で囲む
  • データを受け取るときにはawaitで受け取る

これだけです。
そして、例えば、DefaultControllerを非同期にした場合はこのようになります。


publis async Task < IActionResult > DefaultController(){

    // 非同期で取得
    var item = await _service.GetItems();
    var viewModel = new DefaultViewModel(item)
    return View(); 
}

ちなみに、


var item = await _service.GetItems();

上の部分は、身近な例ではDBからデータを取得するときです。
通常ToList()を使ってメモリ上にデータを蓄えますが、ToListAsync()などとして、非同期でデータを受け取ります。

スポンサードサーチ

【図解】どうなっているの?

ここでは、同期処理、非同期処理、Webにおける非同期処理の利点、タスクとスレッドについて、図を用いて解説してみましょう。

同期処理の場合

クライアントアプリのように表示と裏方の処理を必要とする場合に、同期処理で作ったとしましょう。

図のように、重い処理が走った場合、外部からの入力を受け付けても反応することができません。

非同期処理になると…

今度は、表示用のスレッド(UIスレッド)重い処理をするスレッド(別スレッド)を用意し、非同期で処理した場合を考えます。

この場合は、UIスレッドは、重い処理が走っている間でも(裏で別スレッドで処理しているため)止まることなく、外部からの入力に対して反応できます。

ここまでは、よくある非同期処理の説明です。

Webの非同期処理

Webの場合は少し違います。先ほども言ったように、UIスレッドの代わりはブラウザがやってくれるため、考える必要はありません。

考慮すべき点は、Webサーバーで重い処理が走ったときです。
ですが、サーバー側で重い処理に対して非同期処理がを行ったとしても、結果は待たなければなりません。

同期処理であったとしても非同期処理であったとしても見た目上は変わりません。
しかしながら、非同期処理をしていると、図のように余った分のスレッドを、別のリクエストに応えるスレッドとして使うことができます。

そのため、Webの場合の非同期処理の利点は、資源を有効に使うためになるわけです。

タスクとスレッドの違い

タスクとスレッドは似ていますが、同じものではありません。

スレッドはCPUで実際に処理される単位です。分かりにくい人は、工場のラインのようなものと考えましょう。ベルトコンベヤーにモノが流れていき、途中何かしらのトラブルが起きるとライン全体が止まります。そんなイメージです。

そしてタスクは、大量の工場のラインから、空いているラインを探し、そこに処理を乗っけます。
タスクと言ってしまうと、仕事の単位のように聞こえるため、ここではタスクマンとしましょう。タスクマンはいくつもあるスレッドを管理しているため、空いているスレッド・頑張っているスレッドをすぐに見つけ出すことができます。

ちなみにですが、我々開発者がスレッドを直接使う事はありません(昔はどうだったのかは知りません)。
そしてタスクマンは、空いているスレッドに対し、処理を割り当て、処理を走らせます。

また、別に覚えなくてもいいのですが、このスレッドがたくさんあるところをスレッドプールと言ったりもします。
スレッドプールの利点は、コストを小さく抑えることができる点です。処理が生まれるごとにスレッドを作ると、コストが大きいという事が分かりました。そのため、スレッドプール内でいくつかスレッドを走らせておき、そこに処理を割り当てるという事するようになったわけです。スレッドプールの方がコストを抑えられるという訳です。

まとめ

今回は非同期処理に関することをまとめました。
UIを必要とする場合と、Webの場合では利点が異なること、タスク・スレッドの違いなどを解説しました。