2012-09-09 8 views
72

.NETで結果を収集します同時に、最高のC#4.5(RTM)の方法でラン2つの非同期タスクとは、私は私は2つの長時間実行されるタスクをオフに解雇したい.NET 4.5</p> <p>での作業単純なことだろうと思った何かを得るためにしばらくの間しようとしてきた4.5

で、次の作品を
結果を収集けどので、私はそれを好きではない:私はSleepは、非同期メソッドになりたい

  • ので、それはawaitその他私の方法
  • ちょうど不器用に見えるTask.Run()
  • これは全く新しい言語機能を使用しているとは思わない!

の作業コード:

public static void Go() 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Task.Run(() => Sleep(5000));  
    var task2 = Task.Run(() => Sleep(3000)); 

    int totalSlept = task1.Result + task2.Result; 

    Console.WriteLine("Slept for a total of " + totalSlept + " ms"); 
} 

private static int Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    Thread.Sleep(ms); 
    Console.WriteLine("Sleeping for " + ms + " FINISHED"); 
    return ms; 
} 

非作業コード:

更新:唯一の問題はThread.Sleepで、これは実際に動作し、それを行うための正しい方法です

このコードは、cal l〜Sleep(5000)はすぐにタスクの実行を開始するので、完了するまでSleep(1000)は実行されません。これは、Sleepasyncで、awaitを使用していないか、または.Resultをあまりにも早く呼び出すと、当てはまります。

私は多分私は2つのタスクにStart()を呼び出すことができますが、私は非同期の呼び出しからTask<T>を取得する方法を見つけ出すことはできませんasyncメソッドを呼び出すことにより、非動作してTask<T>を取得する方法があると思いました方法。

public static void Go() 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Sleep(5000); // blocks 
    var task2 = Sleep(1000); 

    int totalSlept = task1.Result + task2.Result; 

    Console.WriteLine("Slept for " + totalSlept + " ms"); 
} 

private static async Task<int> Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    Thread.Sleep(ms); 
    return ms; 
} 
+0

ノート:非同期メソッドは –

+3

ブロックが 'で起こっている違いはありません行く作りますtask1.Result'は 'var task1 = Sleep(5000)'ではありません。これは、awaitキーワードのないSleepメソッドが同期。 – Arvis

答えて

34

非同期プログラミングではSleepではなくTask.Delayを使用し、Task.WhenAllを使用してタスク結果を結合する必要があります。タスクは並行して実行されます。

public class Program 
    { 
     static void Main(string[] args) 
     { 
      Go(); 
     } 
     public static void Go() 
     { 
      GoAsync(); 
      Console.ReadLine(); 
     } 
     public static async void GoAsync() 
     { 

      Console.WriteLine("Starting"); 

      var task1 = Sleep(5000); 
      var task2 = Sleep(3000); 

      int[] result = await Task.WhenAll(task1, task2); 

      Console.WriteLine("Slept for a total of " + result.Sum() + " ms"); 

     } 

     private async static Task<int> Sleep(int ms) 
     { 
      Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount); 
      await Task.Delay(ms); 
      Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount); 
      return ms; 
     } 
    } 
+1

これはすばらしい答えです...しかし、私はそれを実行するまでこの間違いは答えだと思いました。それから私は理解した。実際には5秒で実行されます。そのトリックは、タスクをただちに待つのではなく、代わりにTask.WhenAllを待つことです。 –

3

あなたSleepメソッドは非同期ですが、Thread.Sleepではありません。非同期という考えは、複数のスレッドを開始するのではなく、単一のスレッドを再利用することです。 Thread.Sleepへの同期呼び出しの使用をブロックしているため、動作しません。

Thread.Sleepは、実際にやりたいことを簡略化したものです。実際の実装を非同期メソッドとしてコード化できますか?

複数の同期ブロッキング呼び出しを実行する必要がある場合は、他の場所を見てください。

+0

リチャードに感謝 - はい私は実際に私のサービスコールを使用すると期待どおりに動作するようです –

+0

どのように非同期を実行するには?私は、ファイル交換をたくさん行い、ファイルを待つアプリケーションを持っています。約5秒後に別のプロセスを待っています。 'var x = await y()'や 'y()。wait()'ではなく、まだそれを待っています。注:yは非同期で装飾されています、私はそれが割り当てられている場所ではなく、すべての中ですべてを行うことを期待して編集:私はちょうど私のパートナーに言った、 'Task.Factory'を試してみましょうと彼は言ったこのクラスの一面を打ち破ったときに働いた – deadManN

1

この記事は、多くのことを説明するのに役立ちました。それはFAQスタイルです。

Async/Await FAQ

この部分は、理由を説明し、同じ元のスレッド上で実行さThread.Sleep - 私の初期の混乱につながります。

は、「非同期」のキーワードは、メソッドの呼び出しは のThreadPoolにキューイングさせていますか?新しいスレッドを作成するには?火星の にロケット船を打ち上げるには?

No.前の質問を参照してください。 「async」キーワード は、メソッドがメソッドの内部で使用される可能性があることをコンパイラに示します。待機メソッドは が完了すると が非同期に再開されるようにします。これは、 "async"とマークされたメソッドの内部に "awaits"が存在しない場合、警告を出します。

80
async Task LongTask1() { ... } 
async Task LongTask2() { ... } 
... 
{ 
    Task t1 = LongTask1(); 
    Task t2 = LongTask2(); 
    await Task.WhenAll(t1,t2); 
    //now we have t1.Result and t2.Result 
} 
+1

私はあなたが正しい方法であるt1、t2をタスクとして宣言しているので+1します。 – Minime

+9

このソリューションでは、Goメソッドも非同期でなければならないと考えています。つまり、非同期であることがわかります。呼び出し元の 'Go'メソッドが同期しているが、2つの独立したタスクを非同期的に完了したい場合(つまり、どちらも完了する必要はありませんが、実行が完了する前に完了する必要があります) 。WaitAll' **はより良いでしょう。あなたはawaitキーワードを必要としないので、呼び出し側の 'Go'メソッドは非同期である必要はありません。 ** – AaronLS

+1

voidメソッド: 'async void LongTask1(){...}'にはTask.Resultプロパティがありません。 このような場合には、タスクなしでTaskを使用します: 'async Task LongTask1()'。 – Arvis

0

この時点答えるために:

私はそれはあなたが多分このようSleep機能を書き換えることができ、他の方法

を待つことができるように非同期方法であることがスリープしたいと:

private static async Task<int> Sleep(int ms) 
{ 
    Console.WriteLine("Sleeping for " + ms); 
    var task = Task.Run(() => Thread.Sleep(ms)); 
    await task; 
    Console.WriteLine("Sleeping for " + ms + "END"); 
    return ms; 
} 

static void Main(string[] args) 
{ 
    Console.WriteLine("Starting"); 

    var task1 = Sleep(2000); 
    var task2 = Sleep(1000); 

    int totalSlept = task1.Result +task2.Result; 

    Console.WriteLine("Slept for " + totalSlept + " ms"); 
    Console.ReadKey(); 
} 

は、このコードの意志の出力を実行している:

Starting 
Sleeping for 2000 
Sleeping for 1000 
*(one second later)* 
Sleeping for 1000END 
*(one second later)* 
Sleeping for 2000END 
Slept for 3000 ms 
1

それは今週末です!

public static void Go() { 
    Console.WriteLine("Start fosterage...\n"); 
    var t1 = Sleep(5000, "Kevin"); 
    var t2 = Sleep(3000, "Jerry"); 
    var result = Task.WhenAll(t1, t2).Result; 

    Console.WriteLine("\nMy precious spare time last for only {0}ms", result.Max()); 
    Console.WriteLine("Press any key and take same beer..."); 
    Console.ReadKey(); 
} 

private static async Task<int> Sleep(int ms, string n) { 
     Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
     await Task.Delay(ms); 
     Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
     return ms; 
} 

普通Task.Factory例:

private static Task<int> Sleep(int ms, string n) { 
     return Task.Factory.StartNew(() => { 
      Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
      Thread.Sleep(ms); 
      Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
      return ms; 
     }); 
    } 

TaskCompletionSource例:

private static Task<int> Sleep(int ms, string n) { 
    var tcs = new TaskCompletionSource<int>(); 
    Console.WriteLine("{0} going to sleep for {1}ms :)", n, ms); 
    var t = Task.Factory.StartNew(() => { 
     Thread.Sleep(ms); 
     Console.WriteLine("{0} waked up after {1}ms :(", n, ms); 
     tcs.SetResult(ms); 
    }); 
    return tcs.Task; 
} 
関連する問題

 関連する問題