結論
Task.Run
、async
、await
を使います。
Console.WriteLine("処理を開始");
var task = Task.Run(() =>
{
//時間がかかる処理
for (int i = 0; i < 5; i++)
{
Console.WriteLine("非同期処理中...");
Thread.Sleep(1000);
}
});
//非同期処理が完了するまで待機
while (!task.IsCompleted)
{
Console.WriteLine("処理中...");
Thread.Sleep(1000);
}
Console.WriteLine("処理が終了");
以下に事例別に解説します。
解説
結論の非同期ソース例を実行すると下記のような出力になります。
非同期処理を実施しながら他の処理をしたい場合
Task.Run
を使います。
こちらは結論の非同期処理ソース例を使用することで再現できます。
細かく解説していきます。
改めて解説するソースコードは下記になります。
Console.WriteLine("処理を開始");
var task = Task.Run(() =>
{
//時間がかかる処理
for (int i = 0; i < 5; i++)
{
Console.WriteLine("非同期処理中...");
Thread.Sleep(1000);
}
});
//非同期処理が完了するまで待機
while (!task.IsCompleted)
{
Console.WriteLine("処理中...");
Thread.Sleep(1000);
}
Console.WriteLine("処理が終了");
非同期で実行している箇所は下記になります。
var task = Task.Run(() =>
{
//時間がかかる処理
for (int i = 0; i < 5; i++)
{
Console.WriteLine("非同期処理中...");
Thread.Sleep(1000);
}
});
Task.Run()
を使用することでタスク(非同期処理)を実行することができます。
タスクの状態はtask
変数に格納されています。task
変数はTask
型です。
Task
型で個人的によく使うプロパティと関数は下記になります。
種類 | 名前 | 内容 |
---|---|---|
プロパティ | IsCompleted | タスクが完了したかどうかを示す値を取得します。 |
関数 | Delay | 非同期で待機します。(Thread.Sleepの非同期版) |
関数 | Run | タスクを実行してTask型のオブジェクトを返します。 |
そして、非同期中に実行している箇所は下記になります。 |
while (!task.IsCompleted)
{
Console.WriteLine("処理中...");
Thread.Sleep(1000);
}
Console.WriteLine("処理が終了");
ここではtask
変数のIsCompleted
プロパティを確認してfalse
(実行中)であれば処理中...
と出力しています。そして、IsCompleted
プロパティを確認してtrue
(実行終了)になればwhileループを抜けて処理が終了
と出力しています。
関数を非同期で実行したい場合
async
とawait
を使用します。
下記はWinFormアプリケーションで現在時刻を非同期で更新するソースコードです。
private CancellationTokenSource tokenSource;
private CancellationToken cancelToken;
private async void buttonStart_Click(object sender, EventArgs e)
{
//現在時刻の更新処理を開始する
tokenSource = new CancellationTokenSource();
cancelToken = tokenSource.Token;
await UpdateDateTimeAsync(cancelToken);
}
private void buttonEnd_Click(object sender, EventArgs e)
{
//現在時刻の更新処理を停止する。
tokenSource.Cancel();
}
private async Task UpdateDateTimeAsync(CancellationToken cancelToken)
{
//停止リクエストが来たら終了する。
while (!cancelToken.IsCancellationRequested)
{
labelDateTimeNow.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
await Task.Delay(1000);
}
}
実行した結果は下記の画像です。非同期処理なのでフォームの位置を移動できます。
現在時刻更新開始
ボタンを押下するとbuttonStart_Click
関数が実行されます。
buttonStart_Click
関数ではUpdateDateTimeAsync
関数を非同期処理で実行を開始しています。
関数にasync
をつけることでawait
を実施できるようになります。await
を関数の前につけるとその関数を非同期で実施している間は呼び出し関数に処理を返します。そしてその関数の非同期処理が終了した段階でawait
後のソースコードを実行します。
ソース箇所は下記になります。
private async void buttonStart_Click(object sender, EventArgs e)
{
//現在時刻の更新処理を開始する
tokenSource = new CancellationTokenSource();
cancelToken = tokenSource.Token;
await UpdateDateTimeAsync(cancelToken);
}
現在時刻更新終了
ボタンを押下するとbuttonEnd_Click
関数が実行されます。
buttonEnd_Click
関数ではbuttonStart_Click
関数で実行を開始したUpdateDateTimeAsync
関数に対してキャンセルリクエストを送信しています。
ソース箇所は下記になります。
private void buttonEnd_Click(object sender, EventArgs e)
{
//現在時刻の更新処理を停止する。
tokenSource.Cancel();
}
UpdateDateTimeAsync
関数ではフォームのラベルを1秒おきに現在時刻に更新しています。
もし、実行している途中にキャンセルリクエストが届いている場合はwhileループを抜けて非同期処理を終了しています。
ソース箇所は下記になります。
private async Task UpdateDateTimeAsync(CancellationToken cancelToken)
{
//停止リクエストが来たら終了する。
while (!cancelToken.IsCancellationRequested)
{
labelDateTimeNow.Text = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
await Task.Delay(1000);
}
}
以上です。
非同期処理に関する参考サイト