1

BackGroundWorker を使用して一連のタスクを実行する c# アプリケーションが 1 つあります。

 private void buttonStartCheckOut_Click(object sender, EventArgs e)
        {
                BackgroundWorker checkOuter = new BackgroundWorker();
                checkOuter.DoWork += new DoWorkEventHandler(checkOuter_DoWork);
                checkOuter.RunWorkerAsync();
                checkOuter.RunWorkerCompleted += new RunWorkerCompletedEventHandler(checkOuter_RunWorkerCompleted);
            }

        void checkOuter_DoWork(object sender, DoWorkEventArgs e)
        {
            if (textBoxCICheckOut.Text != "")
                CheckOutCI();

            if (textBoxCACheckOut.Text != "")
                CheckOutCA();

            if (textBoxCAuthCheckOut.Text != "")
                CheckOutCAuth();

            if (textBoxCLCheckOut.Text != "")
                CheckOutCL();

            if (textBoxCCCheckOut.Text != "")
                CheckOutCC();
        }

ご覧のとおり、スレッドは 2 つしかありません。1 つは GUI 用、もう 1 つは二次タスク用です。
すべての機能がいつ終了するかを追跡するのは簡単です。
ここで、CheckOutCI()、CheckOutCA() などに別のスレッドを作成して、より高速にしたいと考えています。5 つのバックグラウンド ワーカーを作成すると、ちょっと汚いように見えます。

質問したい
のは、すべての関数の実行がいつ終了したかを追跡するにはどうすればよいかということです。

いずれかの関数が例外を返した場合、それをユーザーに表示し、ユーザーにユーザーを修正して再試行するように依頼します。私の質問を適切に説明できることを願っています。
彼の投稿に対する私のコメントに従って、wdavo でコードを編集してください。

4

3 に答える 3

4

タスクライブラリの使用を検討します(.NET 4.5以降を実行していると仮定します)。ほとんどの場合、バックグラウンドワーカーよりも使用する方がはるかに優れていると思います。

(.NET 4でもタスクライブラリを使用できますが、Task.WhenAllは4.5でのみ使用可能であることに注意してください)

http://msdn.microsoft.com/en-us/library/dd235618

プログラム全体を書き直さずに、次のように使用する方法の例を示します。

単純な条件付きロジックをボタンに移動します

private void button1_Click(object sender, EventArgs e)
{
  var tasks = new List<Task>();

  if (Text == "A")
  {
    tasks.Add(funcA());
  }

  if (Text == "B")
  {
    tasks.Add(funcB());
  }

  //And so on....

  Task.WhenAll(tasks.ToArray()).ContinueWith(t =>
  {
    if (t.Exception != null)
    {
      //One of the tasks threw an exception
      MessageBox.Show("There was an exception!");
    }
    else
    {
      //None of the tasks threw an exception
      MessageBox.Show("No Exceptions!");
    }
  });

}

タスクをコレクションに追加して、Task.WhenAllを介してすべてのタスクがいつ終了するかを知ることができるようにします。コレクション内のすべてのタスクが完了すると、メッセージボックスが表示されます。コレクション内のいずれかのタスクが例外をスローした場合、「t」のExceptionプロパティが設定されます。特定の例外は、この例外の内部例外として存在します。

スレッデッドコードを個々のタスク/関数に移動します。次のようにチェックアウト関数を作成します。

private Task funcA()
{
  return Task.Factory.StartNew(() =>
  {
    try
    {
      //Code running here will be executed on another thread
      //This is where you would put your time consuming work
      //
      //
    }
    catch(Exception ex)
    {
      //Handle any exception locally if needed
      //If you do handle it locally, make sure you throw it again so we can see it in Task.WhenAll
      throw ex;
    }

    //Do any required UI updates after the work
    //We aren't on the UI thread, so you will need to use BeginInvoke
    //'this' would be a reference to your form
    this.BeginInvoke(new Action(() =>
    {
      //...
    }));

  });
}

これは次のようになります

  • を作成し、スレッドプールからスレッドに対していくつかの作業を行うタスクを実行します
  • 例外がある場合は、ローカルで処理します。「Task.WhenAll」が実行されたときにタスクが失敗したことを確認できるように、例外を再スローします。
  • 作業が完了した後、UIを更新します。クロススレッドの問題を回避するには、BeginInvokeを呼び出してUIスレッドでコードを実行する必要があります。
于 2012-09-04T10:57:13.353 に答える
1

CPU やコアよりも多くのスレッドを起動すると、実際にはアプリケーションが遅くなる可能性があります。CPU よりも多くの CPU バインド スレッドがある場合、OS はスレッド間でより頻繁にコンテキスト スイッチを行う必要があります。これは非常にコストがかかり、OS がスレッドに作業時間を与えるよりも多くの時間をスレッド間のコンテキスト スイッチに費やす可能性があります。

Parallel Task Library の並列の側面を使用して、CPU 間で負荷を自動的に分散できます。例えば:

Action[] actions = new Action[] {CheckOutCI, CheckOutCA, CheckOutCAuth, CheckOutCL, CheckOutCC};
Parallel.ForEach(actions, e=>e());

...これはまさにあなたが望むものではありません。ただし、一般的なアイデアを提供する必要があります。たとえばactions、現在の状況に基づいて入力します。

于 2012-09-04T15:05:34.993 に答える
0

バックグラウンドワーカーで ReportProgress メソッドを使用する必要があります

void checkOuter_DoWork(object sender, DoWorkEventArgs e)
    {
        if (textBoxCICheckOut.Text != "")
            CheckOutCI();
            checkOuter.ReportProgress(completionPercentage,"Error message");

ReportProgress で送信されたデータは、checkOuter_ProgressChanged イベントでキャプチャできます。

 checkOuter_ProgressChanged(object sender,ProgressChangedEventArgs e)
 {
     int percentage = e.ProgressPercentage;
     string message = e.UserState;
 }
于 2012-09-04T10:16:46.403 に答える