C#

C# で Thread.Sleep はあきまへん

ちいさな Tips。サンプルでよく使いますが、しばらく止まって欲しいときってありますよね。そのケースに、Thread.Sleep とかよく使うようです。ただ、これは、あまり使わないほうが良さげですね。

例えば次のようなサンプルを書いてみました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AwaitSample
{

    class Program
    {
        async Task<string> getMessageAsync(string message)
        {
            Console.WriteLine("getMessage!");
            System.Threading.Thread.Sleep(3000);
            Console.WriteLine("finished!");
            return "message:" + message;
        }
        async void executeAsync()
        {
            Console.WriteLine("step 1");
            var result = await getMessageAsync("hello");
            Console.WriteLine(result);
            Console.WriteLine("step 2");
        }
        static void Main(string[] args)
        {
            var program = new Program();
            program.executeAsync();
            Console.WriteLine("step 3");
            Console.ReadLine();
        }
    }
}

結果は step 1, 2, 3 が順に実行されてしまいます。私の想定では、step 1, getMessage! の後は、executeAsync() は非同期なので、先に step 3 が表示されると思っていました。

step 1
getMessage!
finished!
message:hello
step 2
step 3

理由は簡単で、Thread.Sleep Method は、スレッドを止めるメソッドだから、スレッドがブロックされます。だから、この非同期処理が、メインと同じスレッドを使っているとしたら、メイン側のスレッドも停止します。

この場合は、TaskDelay() メソッドを使ってみます。Task.Delay Method (TimeSpan, CancellationToken) こちらは特定の時間の後、Taskの実行が終了しますので、スレッドをブロックしません。

            // System.Threading.Thread.Sleep(3000);
            await Task.Delay(3000);
step 1
getMessage!
step 3
finished!
message:hello
step 2

めでたしめでたし。