0

最近决定编写一个“快速”的 Windows 窗体应用程序来标记我的 MP3 文件。自 .Net 3.0 以来没有对并行性做任何事情,所以我正在研究 Parallel.ForEach 方法来处理我在使用标准 foreach 语句时得到的 UI 锁定。这是一段摘录:

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

您应该非常小心线程安全。您应该确保锁定您正在使用的任何对象,并适当地解锁它。

否则,我知道将 Parallel.ForEach 用于 UI 应该没有问题。

编辑:您可以设置 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 回答
0

好的,我发现实现这一目标的最佳方法是运行以下代码:

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

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

我实际上更新了我的代码以在 foreach 循环中填充一个列表,然后通过 .DataSource 将其分配给 daragrid,而不是直接使用 .Rows 集合。真的应该从一开始就这样做:)

于 2011-12-09T11:44:06.380 回答