Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

最初は、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

TsuyoshiUshio@github
プログラマ。自分の学習用のブログです。内容は会社とは一切関係ありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away