1

複雑で時間のかかる計算を実行し、これらの進行状況を報告するシングルスレッド プログラムがあります。

    private void BtnExecute_Click()
    {
        ComplexCalculation(Object1);
        ComplexCalculation(Object2);
        ComplexCalculation(Object3);
    }

ComplexCalculation メソッドは次のようになります。

private void ComplexCalculation(Object MyObject)
{
   (...do some time consuming operation on MyObject...);
   WriteToTextboxGUI("50% Complete" + MyObject.Name);
   (...do another time consuming operation on MyObject...);
   WriteToTextboxGUI("100% Complete" + MyObject.Name);
}

上記のコードでは、WriteToTextboxGUI(string)メソッドは進行状況で GUI のテキスト ボックスを更新します。

複雑な計算が実行されている間も GUI の応答性を維持できるように、マルチスレッド アプローチを採用したいと考えています。BackgroundWorker私は一般的にかなり読んだことがあります.Net 4.0でTPLが登場したThreadsときにこれがどのように簡素化/改善されたか、.Net 4.5でどのように登場したかを知りたいです.最近のテクノロジでは、次のことができるようにアプリケーションを (比較的単純なコードで) 書き直すことができます。TaskAsyncAwait

  • 複数のスレッドを同時に使用して複雑な計算を実行する
  • 以前と同じように進行状況を GUI に報告する
  • 全体を通してレスポンシブな GUI を維持する

これらの 3 つの基準を満たす簡単な解決策を教えてくれる人はいますか?

PS このアプリケーションはサーバー上では実行されず、デスクトップ上の WPF で実行されます。

4

2 に答える 2

7

IProgress<T>進捗レポートやTask.Runバックグラウンド タスクの開始に使用することをお勧めします。Task.Run最近、が よりも優れてBackgroundWorkerいることを示すブログ シリーズを終了しました。

あなたの場合:

private sealed class ComplexCalculationProgress
{
  public string Name { get; set; }
  public int PercentComplete { get; set; }
}

private void ComplexCalculation(Object MyObject, IProgress<ComplexCalculationProgress> progress)
{
  (...do some time consuming operation on MyObject...);
  if (progress != null)
    progress.Report(new ComplexCalculationProgress { Name = MyObject.Name, PercentComplete = 50 });
  (...do another time consuming operation on MyObject...);
  if (progress != null)
    progress.Report(new ComplexCalculationProgress { Name = MyObject.Name, PercentComplete = 100 });
}

バックグラウンド操作で が呼び出されなくなったためWriteToTextboxGUI、懸念事項がより適切に分離されていることに注意してください。IProgress<T>の設計が、独自のコードのより良い設計を促進することがわかります。

次のように (単純な並列処理を使用して) 呼び出すことができます。

private async void BtnExecute_Click()
{
  var progress = new Progress<ComplexCalculationProgress>(update =>
  {
    WriteToTextboxGUI(update.PercentComplete + "% Complete " + update.Name);
  });
  await Task.WhenAll(
    Task.Run(() => ComplexCalculation(Object1, progress)),
    Task.Run(() => ComplexCalculation(Object2, progress)),
    Task.Run(() => ComplexCalculation(Object3, progress))
  );
}

または、「実際の」並列処理を簡単に使用できます。

private async void BtnExecute_Click()
{
  var progress = new Progress<ComplexCalculationProgress>(update =>
  {
    WriteToTextboxGUI(update.PercentComplete + "% Complete " + update.Name);
  });
  var objects = new[] { Object1, Object2, Object3 };
  await Task.Run(() =>
      Parallel.ForEach(objects, o => ComplexCalculation(o, progress))
  );
}
于 2013-11-15T00:19:21.063 に答える
0

バックグラウンド ワーカーは、これらすべてを簡単に実行できます。

複数のスレッドを同時に使用して複雑な計算を実行する

計算ごとに新しいバックグラウンド ワーカーを使用します。

以前と同じように進行状況を GUI に報告する

ReportProgress() メソッドと ProgressChanged イベントで WorkerReportsProgress=True を使用します。

全体を通してレスポンシブな GUI を維持する

うん。

于 2013-11-14T23:44:38.030 に答える