web-dev-qa-db-ja.com

C#での非同期/待機について

私はC#5.0で非同期/待機について学び始めていますが、まったく理解していません。並列処理にどのように使用できるかわかりません。次の非常に基本的なプログラムを試しました。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task task1 = Task1();
            Task task2 = Task2();

            Task.WaitAll(task1, task2);

            Debug.WriteLine("Finished main method");
        }

        public static async Task Task1()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
            Debug.WriteLine("Finished Task1");
        }

        public static async Task Task2()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
            Debug.WriteLine("Finished Task2");
        }

    }
}
_

このプログラムはTask.WaitAll()の呼び出しをブロックするだけで終了することはありませんが、その理由はわかりません。私は単純なものを見逃しているだけであるか、またはこれに関する適切なメンタルモデルを持っていないに違いないと確信しており、世の中にあるブログやMSDNの記事はどれも役に立たない。

66
Alex Marshall

async/awaitの概要 から始め、 TAPに関するMSDN公式ドキュメント でフォローアップすることをお勧めします。

私のイントロのブログ投稿で言及したように、TPLからの持ち越しであり、純粋なTaskコードでは使用できないasyncメンバーがいくつかあります。 new TaskおよびTask.Startは、Task.Run(またはTaskFactory.StartNew)に置き換える必要があります。同様に、Thread.SleepTask.Delayに置き換える必要があります。

最後に、Task.WaitAllを使用しないことをお勧めします。コンソールアプリは、Task.WhenAllを使用する単一のWaitTaskする必要があります。これらすべての変更により、コードは次のようになります。

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }

    public static async Task MainAsync()
    {
        Task task1 = Task1();
        Task task2 = Task2();

        await Task.WhenAll(task1, task2);

        Debug.WriteLine("Finished main method");
    }

    public static async Task Task1()
    {
        await Task.Delay(5000);
        Debug.WriteLine("Finished Task1");
    }

    public static async Task Task2()
    {
        await Task.Delay(10000);
        Debug.WriteLine("Finished Task2");
    }
}
63
Stephen Cleary

C#タスク、非同期、待機を理解する

C#タスク

タスククラスは非同期タスクラッパーです。 Thread.Sleep(1000)は、実行中のスレッドを1秒間停止できます。一方、Task.Delay(1000)は現在の作業を停止しません。コードを参照してください:

public static void Main(string[] args){
    TaskTest();
}
private static void TaskTest(){
     Task.Delay(5000);
     System.Console.WriteLine("task done");
}

実行すると、「タスク完了」がすぐに表示されます。したがって、Taskのすべてのメソッドは非同期であると想定できます。 TaskTest()をTask.Run(()=> TaskTest())に置き換えた場合、Console.ReadLine();を追加するまで、完了したタスクはまったく表示されません。 Runメソッドの後。

内部的に、タスククラスはステートマシンのスレッド状態を表します。状態マシンのすべての状態には、開始、遅延、キャンセル、停止などのいくつかの状態があります。

非同期および待機

さて、すべてのTaskが非同期かどうか疑問に思うかもしれませんが、Task.Delayの目的は何ですか?次に、非同期と待機を使用して、実行中のスレッドを実際に遅延させましょう

public static void Main(string[] args){
     TaskTest();
     System.Console.WriteLine("main thread is not blocked");
     Console.ReadLine();
}
private static async void TaskTest(){
     await Task.Delay(5000);
     System.Console.WriteLine("task done");
}

async tell caller、私は非同期メソッドです。待ってはいけません。 TaskTest()内で待機して、非同期タスクを待機するように要求します。これで、実行後、プログラムはタスク完了テキストを表示するために5秒待機します。

タスクをキャンセルする

タスクはステートマシンであるため、タスクの実行中にタスクをキャンセルする方法が必要です。

static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
    TaskTest();
    System.Console.WriteLine("main thread is not blocked");
    var input=Console.ReadLine();
    if(input=="stop"){
          tokenSource.Cancel();
          System.Console.WriteLine("task stopped");
     }
     Console.ReadLine();
}
private static async void TaskTest(){
     try{
          await Task.Delay(5000,tokenSource.Token);
     }catch(TaskCanceledException e){
          //cancel task will throw out a exception, just catch it, do nothing.
     }
     System.Console.WriteLine("task done");
}

これで、プログラムの実行中に「停止」を入力して、遅延タスクをキャンセルできます。

13
Andrew Zhu

タスクは実行を開始しないため、終了することはありません。

_Task.Factory.StartNew_でタスクを作成して開始します。

_public static async Task Task1()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
  Debug.WriteLine("Finished Task2");
}
_

サイドノートとして、あなたが本当に非同期メソッドで一時停止しようとしているのであれば、スレッド全体をブロックする必要はなく、単に_Task.Delay_を使用してください

_public static async Task Task1()
{
  await Task.Delay(TimeSpan.FromSeconds(5));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Delay(TimeSpan.FromSeconds(10));
  Debug.WriteLine("Finished Task2");
}
_
11
MerickOWA

非同期と待機は、タスク(スレッド)の完了後に制御を再開するコード位置をマークするマーカーです。概念をデモ形式で説明する詳細なYouTubeビデオがあります http://www.youtube.com/watch?v=V2sMXJnDEjM

必要に応じて、このcoodeprojectの記事を読んで、同じことをより視覚的に説明することもできます。 http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:- “ Async” and“ Await”(Codemarkers)

7