C# 非同期処理編 様々なメソッド① part1-3
今回は非同期処理の様々な機能について紹介していきます.
Wait
waitは指定したタスクの処理が終わるまで,待機するメソッドです.
例えばこんな事があります.
サブタスクの処理中に,メインタスクの処理が終わってしまったらどうなってしまうのか?
図にするとこんな感じです.
では,早速検証していきたいと思います.
static void Main(string[] args)
{
Console.WriteLine("メインタスクの処理開始");
Console.WriteLine("メイン1");
var task = SubTask(); // サブタスクを動かす
Thread.Sleep(1 * 1000); // 1秒待機する
Console.WriteLine("メイン2");
Thread.Sleep(1 * 1000); // 1秒待機する
Console.WriteLine("メイン3");
Console.WriteLine("メインタスクの処理完了");
}
static async Task SubTask()
{
// 別スレッドでタスクを動かす
var task = Task.Run(() =>
{
Console.WriteLine("サブタスクの処理開始");
Console.WriteLine("サブ1");
Thread.Sleep(5 * 1000); // 5秒待機する
Console.WriteLine("サブ2");
Console.WriteLine("サブタスクの処理完了");
});
await task;
}
待機時間に注目しましょう.
サブタスクの待機時間の方が3秒長いです.
実行結果
サブタスクの処理が最後まで完了していない状態で,メインタスクの処理が完了してしまい,プログラムが終了しています.
これを避ける為に,waitを使います.
使い方は,待機したい場所に指定したタスクのwaitメソッドを記述するだけでできます.
メインタスクの処理完了後,待機させる場合,以下のようになります.
static void Main(string[] args)
{
Console.WriteLine("メインタスクの処理開始");
Console.WriteLine("メイン1");
var task = SubTask(); // サブタスクを動かす
Thread.Sleep(1 * 1000); // 1秒待機する
Console.WriteLine("メイン2");
Thread.Sleep(1 * 1000); // 1秒待機する
Console.WriteLine("メイン3");
Console.WriteLine("メインタスクの処理完了");
task.Wait(); // 変更箇所
}
static async Task SubTask()
{
var task = Task.Run(() =>
{
Console.WriteLine("サブタスクの処理開始");
Console.WriteLine("サブ1");
Thread.Sleep(5 * 1000); // 5秒待機する
Console.WriteLine("サブ2");
Console.WriteLine("サブタスクの処理完了");
});
await task;
}
実行結果
メインタスクの処理完了後,サブタスクの処理が完了するまで待機しています.
Result
waitの機能に戻り値を取得するメソッドとして,Resultがあります.
使い方はwaitと同じで,戻り値があるものだと思って貰えればいいです.
static void Main(string[] args)
{
int subsum; // サブタスクからの結果を取得する為の変数
Console.WriteLine("メインタスクの処理開始");
var task = SubTask(); // サブタスクを動かす
// 1から50までの和を求める
int sum = 0;
for (int i = 1; i <= 50; i++)
{
sum += i;
}
Thread.Sleep(3 * 1000); // 3秒待機する
subsum = task.Result; // サブタスクからの結果を待つ
Console.WriteLine(sum + " + " + subsum + " = " + (sum + subsum));
Console.WriteLine("メインタスクの処理完了");
}
static async Task<int> SubTask()
{
int sum = await Task.Run(() =>
{
Console.WriteLine("サブタスクの処理開始");
// 1から100までの和を求める
int sum1 = 0;
for (int i = 1; i <= 100; i++)
{
sum1 += i;
}
Thread.Sleep(5 * 1000); // 5秒待機する
Console.WriteLine("サブタスクの処理完了");
return sum1;
});
return sum;
}
少々わかりにくいと思いますが,Taskの戻り値を取得させる為に,サブタスクをTask<int>にしました.
実行結果
値を取得してからメインタスクの処理を完了させて,プログラムを終了しています.
Thread.SleepとTask.Delay
Thread.Sleepについて,特に説明はしていませんが,
part1-1でも使っていたように,同期的にミリ秒単位で待機するメソッドです.
それに対してTask.Delayは,非同期的に待機します.
簡単に言ってしまえば,
Task.Run(() =>
{
Thread.Sleep();
});
これとやってる事と変わりないです.
awaitと組み合わせて使う事が多いかな?
今回はここまで!