78

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

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 の記事はどれも役に立ちません。

4

5 に答える 5

70

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

自己紹介のブログ投稿で述べたようにTask、TPL からの名残りであり、純粋なasyncコードでは使用されないメンバーがいくつかあります。new Taskおよび(または)Task.Startに置き換える必要があります。同様に、に置き換える必要があります。Task.RunTaskFactory.StartNewThread.SleepTask.Delay

Task.WaitAll最後に、 ;は使用しないことをお勧めします。コンソール アプリはWait、. これらすべての変更により、コードは次のようになります。TaskTask.WhenAll

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");
    }
}
于 2013-01-06T01:19:35.683 に答える
17

C# Task、async、await を理解する

C# タスク

Task クラスは、非同期タスク ラッパーです。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 クラスは State Machine のスレッド状態を表します。ステート マシンのすべての状態には、開始、遅延、キャンセル、停止などのいくつかの状態があります。

非同期で待機

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

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 呼び出し元に伝えます。私は非同期メソッドです。私を待たないでください。TaskTest() 内の await は、非同期タスクの待機を要求します。これで、実行後、プログラムはタスク完了テキストを表示するために 5 秒間待機します。

タスクをキャンセルする

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

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");
}

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

于 2016-09-08T03:37:22.983 に答える
12

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

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");
}
于 2013-01-06T00:21:32.953 に答える
8

async と await は、タスク (スレッド) の完了後に制御を再開するコード位置をマークするマーカーです。これは、概念を実証的な方法で説明する詳細なYouTubeビデオです http://www.youtube.com/watch?v=V2sMXJnDEjM

必要に応じて、同じことをより視覚的に説明するこのコードプロジェクトの記事を読むこともできます。 http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:-「非同期」と「待機」(コードマーカー)

于 2013-09-23T18:51:47.250 に答える
0
static void Main(string[] args)
{
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "Main";
    Console.WriteLine(Thread.CurrentThread.Name + "1");

    TaskTest();

    Console.WriteLine(Thread.CurrentThread.Name + "2");
    Console.ReadLine();
}


private async static void TaskTest()
{
    Console.WriteLine(Thread.CurrentThread.Name + "3");

    await Task.Delay(2000);
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "FirstTask";
    Console.WriteLine(Thread.CurrentThread.Name + "4");

    await Task.Delay(2000);
    if (Thread.CurrentThread.Name == null)
        Thread.CurrentThread.Name = "SecondTask";
    Console.WriteLine(Thread.CurrentThread.Name + "5");
}

このプログラムを実行するawaitと、別のスレッドが使用されることがわかります。出力:

Main1
Main3
Main2
FirstTask4 // 2 seconds delay
SecondTask5 // 4 seconds delay

awaitしかし、両方のキーワードを削除すると、それasyncだけではあまり効果がないことがわかります。出力:

Main1
Main3
Main4
Main5
Main2
于 2021-08-03T19:37:15.310 に答える