LoginSignup
4
7

More than 5 years have passed since last update.

C# 非同期メソッドのタイムアウト

Last updated at Posted at 2017-12-31

非同期メソッドのタイムアウトをさせたかったのでコード試してみた。

最初は、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 が呼ばれたかをチェックする必要がありますが、今回はループ系で使うのでそれでいいのかもですね。ご指摘いただきありがとうございました。

Resource

4
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
4
7