0

は、私はこのような何かを行うべきではない、任意の既知の理由がある場合には、フィードバックを探しています。同じことを達成するための類似の方法はありますか?もっと安全であると考えられますか?Parallel.Foreach +はBackgroundWorker.ReportProgress

コード例:

 int iterations = 0; 
     int count = items.Count; 
     Parallel.ForEach(items, new ParallelOptions() { MaxDegreeOfParallelism = 5 }, item => 
     { 
      iterations++; 
      int percentComplete = (iterations/count) * 100; 
      backgroundWorker.ReportProgress(percentComplete); 
     }; 

追加情報:

私はアイテムを管理する特定のタスクを実行するために必要とWindowsフォームのプログラムを持っています。マルチスレッドを活用することで、はるかに高速化しました。しかし、フォーム全体の進捗状況をプログレスバーに表示する必要があるため、エンドユーザーはプログラムが凍結しているかどうか不思議ではありません。いくつかのケースでは、全体的な仕事に数時間かかることがあります。したがって、進行状況バーは必須です。

+0

.aspx)を "マーキー"に変換します。 –

+0

@Idle_Mindこのシナリオでは、「マーキー」はオプションではないと思われます。残りの時間を知るためには、完了した作業の距離を確認することが重要です。 – SED

+1

上のコードは**意味のある**進捗状況をどのように報告しますか? –

答えて

1

私はそれは賢明ではないと思い、そしておそらくは複数のスレッドが同じBackGroundWorkerと通信できるように許可されていません。あなたの例では、5のようなスレッドの限られた量を、持っている場合

は、各スレッドは、独自の進捗状況を報告し、独自のBackgroundWorkerを使用することを検討します。

すべての進捗報告の受信機が報告を受けて、実際の進捗状況について決定し、興味を持っている人にそれを報告しなければなりません。

class MyLongProgress : IDisposable 
{ 
    public MyLongProgress() 
    { 
     for (int i=0; i<maxNrOfParallelProcesses; ++i) 
     { 
      var createdBackGroundWorker = this.CreateBackGroundWorker(); 
      createdBackGroundWorker.ReportProgress += this.OnProgressReport; 
      backGroundWorkers.Add(createdBackGroundWorker); 
     } 
    } 
    // TODO: implement Disposable pattern that Disposes the background workers 
    private readonly List<BackGroundWorker> backGroundWorkers = new List<BackGroundWorker>(); 

    public void StartLongProcess() 
    { 
     // start your long progress, which involves starting the backGroundWorkers 
     // These backGroundWorkers will report progress via OnProgressReport 
    } 

    private void OnProgressReport(object sender, ...) 
    { 
     var myBackGroundWorker = (BackGroundWorker)sender; 
     // calculate the actual progress using earlier received progress reports 
     MyProgressReport report = ... 
     OnReportProgress(report); 
    } 

    public event EventHandler<MyprogressReport> ReportProgrogress; 

    protected virtual void OnReportProgress(MyProgressReport report) 
    { 
     this.ReportProgress?.Invoke(this, report); 
    } 
} 

また、BackGroundWorkersを作成して、StartLongProcessの間に処分することもできます。その場合、IDisposableは必要ありません。

+0

"...おそらく、複数のスレッドが同じBackGroundWorkerと通信できるようにすることさえできませんでした。私のサンプルコードはうまくいき、このテクニックには既知の問題はありません。私の進歩バーは私が期待する通りに更新されます。あなたがしたことと同じことを言っている同僚の話によれば、私はこの質問に明確化を求める理由です。どのように、あるいはなぜあなたの提案されたアプローチがより良いかを詳しく説明できますか? – SED

1

私はハラルドが彼の答えでお金の上にいると思います。 私は、バックグラウンドワーカーが1人の場合、this linkの例を使用しました。

次のスニペット(上記のリンクからコピーされています)でどのように動作するかは、良い気分になります。私はおそらくDoWorkEventHandler代理人のコレクションを許可し、それぞれのためにBackgroundWorkerを作成するためにそれをベースとして使用できると思います。ただ[ProgressBar.Style()プロパティ(https://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.style(V = vs.110)を設定

 private void button4_Click(object sender, EventArgs e) 
     { 
     // Create dialog. 
     ProgressWithCancel dlgProgress = new ProgressWithCancel("Testing progress", LongOperation); 

     // Show dialog with Synchronous/blocking call. 
     // LongOperation() is called by dialog. 
     dlgProgress.ShowDialog(); // Synchronous/blocking call. 
     } 

     private void LongOperation(object sender, DoWorkEventArgs e) 
     { 
     BackgroundWorker worker = sender as BackgroundWorker; 

     int max = 20; 
     for (int i = 0; i < max; i++) 
     { 
      if (worker.CancellationPending) // See if cacel button was pressed. 
      { 
       System.Threading.Thread.Sleep(2000); // Similate time for clean-up. 
       break; 
      } 

      int percent = i * 100/max; 

      string userState = percent.ToString(); // render a string to display on the progress dialog. 

      // Append to string just to show multi-line user-status info. 
      if (percent >= 45 && percent <= 55) { userState += "Half way"; } 
      if (percent >= 85) { userState += "Almost done"; } 

      worker.ReportProgress(percent, userState); // Report percent and user-status info to dialog. 

      System.Threading.Thread.Sleep(800); // Simulate time-consuming operation 
     } 
     } 


// Implementation (in ProgressWithCancel.cs) 

namespace ProgressWithCancel 
{ 
    public partial class ProgressWithCancel : Form 
    { 
     public ProgressWithCancel(string whyWeAreWaiting, DoWorkEventHandler work) 
     { 
     InitializeComponent(); 
     this.Text = whyWeAreWaiting; // Show in title bar 
     backgroundWorker1.DoWork += work; // Event handler to be called in context of new thread. 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
     label1.Text = "Cancel pending"; 
     backgroundWorker1.CancelAsync(); // Tell worker to abort. 
     btnCancel.Enabled = false; 
     } 

     private void Progress_Load(object sender, EventArgs e) 
     { 
     backgroundWorker1.RunWorkerAsync(); 
     } 

     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
     progressBar1.Value = e.ProgressPercentage; 
     label1.Text = e.UserState as string; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
     Close(); 
     } 

    } 
} 
+0

これは、私の質問の重要な部分である複数のタスクを同時に実行するために、どのようなマルチスレッドを利用するのかわかりません。 – SED

+0

その例はありません。それはちょうど1つを使用します。私はそれを例として掲示していましたが、それを出発点として使うことができると述べましたが、複数のBackgroundWorkersで動作するように更新しました。 –

関連する問題