0

最近、MP3 ファイルにタグを付けるための「クイック」Windows フォーム アプリを作成することにしました。.Net 3.0 以降、並列処理については何も行っていないため、標準の foreach ステートメントを使用しているときに発生する UI ロックを処理する Parallel.ForEach メソッドを調べています。ここに抜粋があります:

var i = 1;
var files = new List<string>(); // File list is populated using recursive method.

foreach(var f in files) {
    // Add a row
    var row = dgvList.Rows[dgvList.Rows.Add()];

    // Update label
    lblSummary.Text = string.Concat("Processing... ", i);
    // Do things with row

    // Increment progress bar
    progressBar.PerformStep();
    i++;
}

Parallel.ForEach() の簡単な使用法を理解しましたが、その特定のメソッドを使用して UI を更新する必要があるかどうかわかりません。助言がありますか?

4

3 に答える 3

0

OK、これを達成するための最良の方法は、次のようなものを実行することです。

// Kick off thread
Task.Factory.StartNew(delegate{
     foreach(var x in files) {
         // Do stuff

         // Update calling thread's UI
         Invoke((Action)(() => {
              progressBar.PerformStep();
         }));
     }
}

実際にコードを更新して、foreachループ内にリストを設定し、.Rowsコレクションを直接操作する代わりに、.DataSourceを介してそれをdaragridに割り当てました。最初から本当にそうすべきだった:)

于 2011-12-09T11:44:06.380 に答える
0

スレッドセーフには細心の注意を払う必要があります。使用しているオブジェクトは必ずロックし、適切にロック解除してください。

それ以外の場合は、UI に Parallel.ForEach を使用することについて私が知っている問題はありません。

編集: Form.CheckForIllegalCrossThreadCalls=false を設定して、スレッドセーフのチェックを無効にすることができます。
ここにいくつかのドキュメントがあります: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx
これは機能しますが、スレッドを気にする必要があるため、危険です-安全は自分で。

これに対処するより良い方法は、UI ロジックに呼び出しパターンを使用することですが、UI 操作自体が UI スレッドで呼び出されるため、並列性が損なわれます。
ただし、これは物事を行うための安全な方法です。
ドキュメント: http://msdn.microsoft.com/en-us/library/ms171728.aspx

于 2011-12-05T09:44:01.333 に答える
0

UI スレッドから並列ライブラリを使用しないでください。並列ライブラリは、複数のスレッドでタスクのグループを実行するため、その中に UI 関連のコードを記述しないでください。

ビジネス ロジックをバックグラウンド タスクに移動し、UI スレッドで実行するディスパッチャを使用して UI を更新する必要があります。

MSDNが言うように

It is important to keep your application's user interface (UI) responsive. If an 
operation contains enough work to warrant parallelization, then it likely should not
be run that operation on the UI thread. Instead, it should offload that operation to 
be run on a background thread. For example, if you want to use a parallel loop to 
compute some data that should then be rendered into a UI control, you should consider
executing the loop within a task instance rather than directly in a UI event handler. 
Only when the core computation has completed should you then marshal the UI update back 
to the UI thread.

そして最も重要なことは、Paralle.Foreach から UI スレッドを更新しようとする場合です。

If you do run parallel loops on the UI thread, be careful to avoid updating UI 
controls from within the loop. Attempting to update UI controls from within a parallel 
loop that is executing on the UI thread can lead to state corruption, exceptions, 
delayed updates, and even deadlocks, depending on how the UI update is invoked
于 2011-12-05T09:51:35.720 に答える