2012-11-15 13 views
5

として罰金作品:タスク・ライブラリーのコードフリーズパラレル - この質問は、私が求めていた前の質問へのフォローアップでのWindowsコンソールアプリケーション

How to Perform Multiple "Pings" in Parallel using C#

私がすることができました受け入れられた答え(Windowsコンソールアプリケーション)を動作させますが、Windowsフォームアプリケーションでコードを実行しようとすると、次のコードはTask.WaitAll(pingTasks.ToArray())を含む行でフリーズします。実行しようとしているコードは次のとおりです。

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Net.NetworkInformation; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 

      List<String> addresses = new List<string>(); 

      for (Int32 i = 0; i < 10; ++i) addresses.Add("microsoft.com"); 

      List<Task<PingReply>> pingTasks = new List<Task<PingReply>>(); 
      foreach (var address in addresses) 
      { 
       pingTasks.Add(PingAsync(address)); 
      } 

      //Wait for all the tasks to complete 
      Task.WaitAll(pingTasks.ToArray()); 

      //Now you can iterate over your list of pingTasks 
      foreach (var pingTask in pingTasks) 
      { 
       //pingTask.Result is whatever type T was declared in PingAsync 
       textBox1.Text += Convert.ToString(pingTask.Result.RoundtripTime) + Environment.NewLine; 

      } 

     } 

     private Task<PingReply> PingAsync(string address) 
     { 
      var tcs = new TaskCompletionSource<PingReply>(); 
      Ping ping = new Ping(); 
      ping.PingCompleted += (obj, sender) => 
      { 
       tcs.SetResult(sender.Reply); 
      }; 
      ping.SendAsync(address, new object()); 
      return tcs.Task; 
     } 

    } 

} 

凍結する理由はありますか?

答えて

16

WaitAllはすべてのタスクを待機しているため、UIスレッドを使用しているためUIスレッドがブロックされているため、フリーズしています。 UIスレッドをブロックすると、アプリケーションがフリーズします。

あなたがC#5.0にいるので、何をしたいかは、代わりにawait Task.WhenAll(...)です。 (また、そのイベントハンドラをその定義にasyncとマークする必要があります)。コードの他の側面は変更する必要はありません。それはうまくいくでしょう。

awaitは、タスクで実際に「待機」しません。それが何をするのかは、待っているときには、あなたが実行しているタスク(この場合は、すべて)に続き、その継続でメソッドの残りの部分が実行されます。その後、その継続を配線した後、メソッドを終了して呼び出し元に戻ります。つまり、このクリックイベントはすぐに終了するため、UIスレッドはブロックされません。

(リクエストに応じて)C#4.0を使用してこれを解決したい場合は、WhenAllを5.0から追加してから最初から書き込む必要があります。ここで私はちょうどホイップアップです。ライブラリの実装ほど効率的ではないかもしれませんが、うまくいくはずです。ここで

public static Task WhenAll(IEnumerable<Task> tasks) 
{ 
    var tcs = new TaskCompletionSource<object>(); 
    List<Task> taskList = tasks.ToList(); 

    int remainingTasks = taskList.Count; 

    foreach (Task t in taskList) 
    { 
     t.ContinueWith(_ => 
     { 
      if (t.IsCanceled) 
      { 
       tcs.TrySetCanceled(); 
      } 
      else if (t.IsFaulted) 
      { 
       tcs.TrySetException(t.Exception); 
      } 
      else //competed successfully 
      { 
       if (Interlocked.Decrement(ref remainingTasks) == 0) 
        tcs.TrySetResult(null); 
      } 
     }); 
    } 

    return tcs.Task; 
} 

はsvickのコメントにthis suggestionに基づいて別のオプションです。

public static Task WhenAll(IEnumerable<Task> tasks) 
{ 
    return Task.Factory.ContinueWhenAll(tasks.ToArray(), _ => { }); 
} 

今、私たちはWhenAllを持っていることを、私たちはまさにそれを使用する必要があるだけでなく、継続、代わりのawait。代わりにWaitAllのあなたが使用します:5.0オプションがきれいで、これはあまりにも合理的にシンプルなユースケースである理由

MyClass.WhenAll(pingTasks) 
    .ContinueWith(t => 
    { 
     foreach (var pingTask in pingTasks) 
     { 
      //pingTask.Result is whatever type T was declared in PingAsync 
      textBox1.Text += Convert.ToString(pingTask.Result.RoundtripTime) + Environment.NewLine; 
     } 
    }, CancellationToken.None, 
    TaskContinuationOptions.None, 
    //this is so that it runs in the UI thread, which we need 
    TaskScheduler.FromCurrentSynchronizationContext()); 

を今、あなたは参照してください。

+1

はい!私は 'Task.WaitAll()'の代わりに 'await Task.WhenAll()'を使用しなければなりませんでした...私はまた、 'async'をbutton_clickイベントに追加しなければなりませんでした。私はあなたにこの質問に答えるための信用を与えるでしょう。ありがとう! – HydroPowerDeveloper

+0

完全性のために、5.0より前のC#を使用しているときに代替ソリューションを入手できますか? – Pete

+0

私は2番目のピートの要求...私も<5.0解決策を知りたいです。 – HydroPowerDeveloper

関連する問題