C#でのasync&awaitとTaskの使い方と非同期の考え方をわかりやすく解説#5

当サイトではアフィリエイト広告を利用しています。

C#での非同期プログラミング

async await編

async awaitとは何か?

async&awaitとは.NETFramework4.5で追加された機能で,非同期処理をより同期的に記述できる機能です。

async awaitを使うとどんな良いことがあるのか?

async&awaitは前述のTaskと組み合わせることで同期プログラミングをしているような書き方で非同期プログラミングができます。.NETFramework4.5以降の開発環境でプログラミングしている場合は積極的にasync&awaitを使用しましょう。

async awaitを使わないとどんな悪いことがあるのか?

async&awaitを使わない場合は,UIスレッドに戻す記述を前述のTaskで紹介したContinueWithを使用して記述する必要があるので,async&awaitに比べると可読性は下がります。

async awaitの使い方

public partial class ThreadForm5 : Form
{
    private int _count = 0;
    public ThreadForm5()
    {
        InitializeComponent();
    }

    private void CountButton_Click(object sender, EventArgs e)
    {
        this.CountButton.Text = _count++.ToString();
    }

    /// <summary>
    /// AsyncAwaitボタンクリック
    /// </summary>
    /// <param name="sender">コントロール</param>
    /// <param name="e">イベント引数</param>
    private async void AsyncAwaitButton_Click(object sender, EventArgs e)
    {
        var dtos = await Task.Run(() => GetDataAsync());
        dataGridView1.DataSource = dtos; 
    }

    /// <summary>
    /// 検索処理
    /// </summary>
    /// <returns></returns>
    private List<DTO> GetDataAsync()
    {
        var result = new List<DTO>();
        for (int i = 0; i < 5; i++)
        {
            System.Threading.Thread.Sleep(1000);
            result.Add(new DTO(i.ToString(), DateTime.Now.ToString("HH:mm:ss")));
        }

        return result;
    }
}
AsyncAwaitButton_Clickイベント
    private async void AsyncAwaitButton_Click(object sender, EventArgs e)
    {
        var dtos = await Task.Run(() => GetDataAsync());
        dataGridView1.DataSource = dtos; 
    }

まず3行目の「var dtos = await Task.Run(() => GetDataAsync());」ですが,Task.Run以降の部分はTaskの時と同じです。Taskの例にあったContinueWith以降の記述がなくなっています。Task.Runの直前にawaitというキーワードがあります。このキーワードがあるとTask.Runで実行している非同期処理の完了を待ってから,それ以降の処理がUIスレッド上で行われるようになります。

この例で言うと,非同期処理GetDataAsyncの処理が終わってから戻り値がdtosにセットされるタイミング以降はボタンクリック時に動作するUIスレッドに戻ってきているので,何の記述もなく普通に「dataGridView1.DataSource = dtos; 」を記述することができます。これはまさに同期的プログラミングの例と同じになります。
※記述は一行にして「dataGridView1.DataSource = await Task.Run(() => GetDataAsync());」でも問題ありません。

1行目のasyncのキーワード決まりごとです。asyncキーワードで修飾されていないメソッドではawaitキーワードは使用できない決まりになっています。awaitを使う場合は必ずasyncキーワードが必要になります。

GetDataAsyncメソッド

GetDataAsyncはTaskの例のときと同じです。async&awaitはTaskと組み合わせて使っているので,このあたりは同じです。

async&awaitの書き方まとめ

TaskのときはContinueWithで書かなければいけなかったUIスレッド上の処理が,一切不要になったため,非同期処理の書き方としては,完成されたものになっていると思います。

まとめ

.NETFramework4.0より前の場合は極力ThreadPoolをしようし,監視処理などスレッドを占有する場合のみThreadクラスを使用する※今回は解説しませんでしたが,監視処理をするのであればSystem.Threading.Timerが良いでしょう。

.NETFramework4.0を使うならThreadPoolの代わりにTaskを使う。
.NETFramework4.5以降を使うならTaskとasync&awaitを組み合わせて使う。