非同期メソッドのタイムアウトをさせたかったのでコード試してみた。
最初は、Task.Wait()
を使用しようとしたけど、結局Task.Result
で待ち合わせるので、結局待ち合わせてしまう。Task.WhenAny
を使えばうまくいく。Task.WhenAny
は複数のタスクのうち、どれかが終われば、先に進むタスク。その性質を利用している。
自分用のメモ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PollingSpike
{
class Program
{
static void Main(string[] args)
{
new Program().MainAsync().GetAwaiter().GetResult();
}
private async Task MainAsync()
{
var timeout = TimeSpan.FromSeconds(5);
Console.WriteLine($"Timeout: {timeout.TotalMilliseconds}");
var task = pollingMessageAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task)
{
Console.WriteLine($"Result: {task.Result.ToString()}");
} else
{
Console.WriteLine("Result1 timeout");
}
var task2 = pollingMessageTimeOutAsync();
if (await Task.WhenAny(task2, Task.Delay(timeout)) == task2)
{
Console.WriteLine($"Result2: {task2.Result.ToString()}");
} else
{
Console.WriteLine("Result2 timeout");
}
Console.ReadLine();
Console.WriteLine("Task3 has been started");
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var token = cts.Token;
try
{
var task3 = await pollingMEssageTimeOutByCancellationToken(token);
Console.WriteLine($"Result3 this is not called {task3}");
} catch (TaskCanceledException e)
{
Console.WriteLine($"Task3 has been canceled by timeout {e.Message}");
Console.ReadLine();
}
}
private async Task<string> pollingMessageAsync()
{
await Task.Delay(TimeSpan.FromSeconds(3));
return "Finish! 3 sec";
}
private async Task<string> pollingMessageTimeOutAsync()
{
await Task.Delay(TimeSpan.FromSeconds(10));
return "Finish! 10 sec";
}
private async Task<string> pollingMEssageTimeOutByCancellationToken(CancellationToken token)
{
await Task.Delay(TimeSpan.FromSeconds(10), token);
return "Finish! 10 sec with cancellation token";
}
}
}
追記 2017/12/31 17:20
Cancellation token がよさげということなので、そのパターンも実装してみました。普通のインターフェイスも実装しているから
それがいいのかな。ちなみに、Cancellation Token を実装すると、メソッド側で、Cancellation token が呼ばれたかをチェックする必要がありますが、今回はループ系で使うのでそれでいいのかもですね。ご指摘いただきありがとうございました。