5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

c# async voidでawait Task.Run()失敗の巻

Last updated at Posted at 2019-06-19

これで失敗.png
##はじめに

.cs
await Task.Run(() => HeavyMethod());

このようなサンプル良く見かけますね。何気なく使っていました。
実はこれで失敗したんです。
私は最近までTask.Runで包み込んでやると上記サンプルのようにHeavyMethodもTaskになるものだと勘違いしていました。
後から調べたらHeavyMethodの中身が問題で、awaitを使う場合async voidはUIのイベント処理以外は使うなと色々な所に書かれていますね。

例えばコマンド(Start)を送った後2秒待っでコマンド(End)を送る処理で、Start~Endが終わってから次の処理を実行することが条件になる場合、async voidを使うと期待通り動かないことがあります。
ご存知の方にはそれほど大げさなことでは無いかも知れませんが...書き留めます。

##async voidでは意図した動作にならない
上記のサンプル物まねでやった結果です。

.cs
private async void button1_Click(object sender, EventArgs e)
{
    for(var i = 0; i < 3; i++)
    {
        await Task.Run(() => DelayMethodByAsyncVoid(i));
    }
}

async void DelayMethodByAsyncVoid(int id)
{
    System.Console.WriteLine("Start "+id);
    await Task.Delay(2000);
    System.Console.WriteLine("End " + id);
}
Start 0
Start 1
Start 2
End 2
End 1
End 0

ラムダ式の中はTaskですがDelayMethodByAsyncVoid(i)の中はTaskでは無いのでawait Task.DelayのところでTask完了となっているみたいです。
DelayMethodByAsyncVoidは非同期で動きます。
そもそもMethod 1つを呼ぶのにTask.Runを使うのが良いのかという疑問もあります。

##ラムダ式の中に処理を書く
ラムダ式の中にDelayMethodByAsync(i)の処理を書くとすべての処理がTaskとなりうまくいきます。

.cs
private async void button2_Click(object sender, EventArgs e)
{
    for(var i = 0; i < 3; i++)
    {
        await Task.Run(async () =>
        {
            System.Console.WriteLine("Start " + i);
            await Task.Delay(2000);
            System.Console.WriteLine("End " + i);
        });
    }
}
Start 0
End 0
Start 1
End 1
Start 2
End 2

###async Taskを定義する
何でもかんでもTask.Runでやっていたのですが複数個所から呼ばれる場合async Taskで定義するのがすっきりします。

.cs
private async void button3_Click(object sender, EventArgs e)
{
    for(var i = 0; i < 3; i++)
    {
        await DelayMethodByTask(i);
    }
}

async Task DelayMethodByTask(int id)
{
    System.Console.WriteLine("Start "+id);
    await Task.Delay(2000);
    System.Console.WriteLine("End " + id);
}
Start 0
End 0
Start 1
End 1
Start 2
End 2

##動作環境

開発環境
Visual Studio Community 2017

ターゲットフレームワーク
.NET Fremawork 4.6.1
5
7
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
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?