2016-12-04 36 views
0

私は現在、多くの時間がかかるタスクを実装しています。 基本的に、私がしたいのは、foreachループ内で複数のタスクを実行することです。 Parallel.ForEachを使用して私のUIをフリーズしようとしました。私は一度に10のuidのように呼びたいと思う。ここでループ内で複数のスレッドを実行する方法

foreach (var uid in listBox2.Items) 
       { 
        if (StopEmail) break; 
        Application.DoEvents(); 
        string jsonstring = GetEmails(uid.ToString(), token); 
        if (jsonstring != null) 
        { 
         label6.Text = " Current UID: " + listBox2.Items.IndexOf(uid); 
         dynamic jsonResponse = JsonConvert.DeserializeObject(jsonstring); 
         string idstt = jsonResponse["email"]; 
         if (idstt != null) 
         { 
          listBox3.Items.Add(idstt); 
          label4.Text = "Total Emails: " + listBox3.Items.Count.ToString(); 

         } 
        } 
       } 

は私Parallel.ForEachコード:

var files = listBox2.Items.Cast<String>().ToList(); 
Parallel.ForEach(files, uid => 
{ 
    Application.DoEvents(); 
    string jsonstring = GetEmails(uid.ToString(), token); 
    if (jsonstring != null) 
    { 
     this.Invoke(new MethodInvoker(delegate() 
     { 
      label6.Text = " Current UID: " + listBox2.Items.IndexOf(uid); 
     })); 

     dynamic jsonResponse = JsonConvert.DeserializeObject(jsonstring); 
     string idstt = jsonResponse["email"]; 
     if (idstt != null) 
     { 
      this.Invoke(new MethodInvoker(delegate() 
      { 
       listBox3.Items.Add(idstt); 
       label4.Text = "Total Emails: " + listBox3.Items.Count.ToString(); 
      })); 
     } 
    } 
}); 
+0

これがUIをフリーズしている場合は、UIスレッドでforeachの外側部分を実行しています。バックグラウンドワーカーでUIスレッドを実行して、描画を続けるようにしてください。バックグラウンドスレッドから、parallel.ForEachを使用して試してください。 – meganaut

+0

はこのWPFまたはWinformsです –

+0

@meganautはparallel.foreachコードの編集を確認してください。 –

答えて

2

ここでは、Microsoftのリアクティブフレームワーク(NuGet "System.Reactive.Windows.Forms")を使用します。すべてうまくqueryで扱われるように遅い部分がGetEmailsコールである

var uids = listBox2.Item.Cast<String>().ToArray(); 

var query = 
    from uid in uids.ToObservable() 
    from jsonstring in Observable.Start(() => GetEmails(uid, token)) 
    where jsonstring != null 
    select new { uid, jsonstring }; 

IDisposable subscription = 
    query 
     .ObserveOn(this) 
     .Subscribe(x => 
     { 
      label6.Text = " Current UID: " + listBox2.Items.IndexOf(x.uid); 
      dynamic jsonResponse = JsonConvert.DeserializeObject(x.jsonstring); 
      string idstt = jsonResponse["email"]; 
      if (idstt != null) 
      { 
       listBox3.Items.Add(idstt); 
       label4.Text = "Total Emails: " + listBox3.Items.Count.ToString(); 
      } 
     }); 

その後、あなたはこれを行うことができます。

.ObserveOn(this)コールはコードをUIスレッドに戻してマーシャリングしますので、乱雑ではありません.Invoke呼び出しが必要です。

最後に、計算を早く終了するには、subscription.Dispose()と呼んでください。

+0

Yuhoo!見える、素晴らしい。 –

0

Task.Runコールの内側にあなたのParallel.ForEachをラップ:

var files = listBox2.Items.Cast<String>().ToList(); 
Task task = Task.Run(() => { 

    Parallel.ForEach(files, uid => 
    { 
     // remove the `Application.DoEvents()` call, it is unnecessary 
     // ... 
    } 

}); 

を代わりにForEachからデータを返すために、より良いデザインかもしれメソッドを.Invokeと呼ぶのではなく、awaitを使用してUIを更新することもできますForEachが完成しましたが、これはループと目的のUXの性質によって異なります。

+0

私は一度に10のuidのように動かすことができます。私は10つのタスクを意味します –

+2

@SherryMemonなぜ具体的に10? 'Parallel.ForEach'メソッドは、あなたのコンピュータが持っているハードウェアスレッドの数を確認し、正しい数を実行して、リストが最適に処理されるようにします。ですから、ForEachのスレッド数をオーバーライドするのは非常に良い理由が必要です。 – Dai

+0

チェックされているuidの数とそのすべてをチェックし続けたいと思います。それが私がUIを更新している理由です。 –

関連する問題