前回は「ファイルの読み書き」をやりました。

今回は、少し高度ですが、現代のプログラミングに欠かせないasync/await(エイシンク・アウェイト)です。「非同期処理」とも呼ばれます。少し難しく感じても大丈夫。考え方をつかめば十分です。

async/await とは、時間のかかる処理を待つ間、他のことを止めないための仕組みです。

「待ち時間」が、問題になる

プログラムには、時間のかかる処理があります。

  • インターネットからデータを取ってくる
  • 大きなファイルを読み込む
  • データベースに問い合わせる

これらは、一瞬では終わりません。数秒かかることもあります。

問題は、第1回でやった「プログラムは上から順番に動く」というルール。順番に動くということは、時間のかかる処理が終わるまで、次に進めないということです。

var data = GetDataFromInternet();   // ここで5秒かかるとする
Console.WriteLine("取得完了");       // 5秒待たないと、ここに来ない

この5秒の間、プログラムは何もできずに固まります。アプリなら、画面が固まって、ボタンも押せない。あの「応答なし」状態です。

料理でたとえると

料理を考えてみてください。

お湯を沸かすのに10分かかるとします。お湯が沸くまで、コンロの前でただ10分待つでしょうか。ふつうは、その間に野菜を切ったり、皿を準備したりしますよね。

「待ち時間に、他のことをやる」。これが、async/await の発想です。

  • 待つだけ(同期) … お湯が沸くまで、何もせず10分立ち尽くす
  • 待たずに進む(非同期) … お湯を火にかけたら、沸く間に他の作業をする

書き方を見てみる

ファイルを読む処理を、非同期で書いてみます。

async Task ReadFileAsync()
{
    Console.WriteLine("読み込み開始");

    string text = await File.ReadAllTextAsync("big_file.txt");

    Console.WriteLine("読み込み完了");
}

新しい言葉が2つ出てきました。

  • await(アウェイト)… 「この処理を待つ。でも、待つ間に他のことを止めない」
  • async(エイシンク)… 「このメソッドの中で await を使いますよ」という印

await File.ReadAllTextAsync(...) で、ファイル読み込みを待ちます。でも、ふつうの待ち方と違って、待つ間にプログラム全体は固まりません。お湯を火にかけて、他のことをできる状態です。

async と await は、ペア

ルールはシンプルです。

  • await を使いたいなら、そのメソッドに async をつける
  • async をつけたメソッドの戻り値は、ふつう Task になる
async Task DoSomethingAsync()   // async をつける
{
    await ...                   // 中で await を使う
}

Task(タスク)は、「これは時間のかかる作業ですよ」という戻り値の型だと思ってください。第16回でやった voidint の仲間で、「非同期版の戻り値」です。

そして、慣習として、非同期メソッドの名前は Async で終わらせますReadFileAsync のように)。「これは非同期だよ」と分かるようにする、親切な印です。

なぜ、今のプログラミングで重要なのか

現代のアプリは、ネットワークを使うものがほとんどです。Webサイト、スマホアプリ、業務システム——どれも、サーバーと通信します。

その通信は、時間がかかります。もし同期(待つだけ)で書いたら、通信のたびにアプリが固まってしまう。だから、現代のプログラミングでは、async/await が当たり前に使われます

「時間のかかる処理=固まる」を避けるための、必須の仕組み。だから、入門の最後に近いこの段階で、知っておく価値があります。

つまずきポイント

ここは、一度で完全に理解できなくて、当たり前の難所です。最初は、3つだけ押さえれば十分です。

ひとつ、何のためか。「時間のかかる処理で、固まらないため」。

ふたつ、await と async はペア。「await を使うメソッドには async をつける」。

みっつ、await は『待つけど固まらない』。ふつうの待ちと違う、という感覚。

細かい仕組み(Task の中身、スレッドの動き…)は、後から少しずつで大丈夫です。まずは「ネットワークやファイルなど、時間のかかる処理には async/await を使うんだな」と知っておく。それで、十分なスタートです。

まとめ

async/await は、時間のかかる処理を、待たずに進める仕組み。

async Task ReadFileAsync()              // async をつける
{
    string text = await File.ReadAllTextAsync("file.txt");  // await で待つ
}
  • 時間のかかる処理で、プログラムが固まるのを防ぐ
  • await … 待つけど、全体は止めない
  • async … await を使うメソッドにつける印(ペア)
  • ネットワーク通信などで、現代では必須

一度で分からなくても大丈夫。「固まらないための仕組み」とだけ、覚えておいてください。