Parallel.ForEach and DataGridViewRow

时间:2015-09-30 23:10:07

标签: c# datagridview foreach parallel-processing

I'm having an issue converting .AsParallel to the Parallel.ForEach. I have a DataGridView and i'm putting some values in the first column of it after that with ForEach loop i'm sending the value to method and getting a return value then i'm putting the return value to second column.

At the beginning; i was using ForEach loop but it takes too much time, then i decided to use .AsParallel but i think, in my situation, it might be better to use Parallel.ForEach but i couldn't make it work with datagridviewrow.

ForEach Method :

 foreach (DataGridViewRow dgvRow in dataGrid1.Rows)
 {
     // SOME CODES REMOVED FOR CLARITY
     string data1 = row.Cells[1].Value;
     var returnData = getHtml(data1);
     row.Cells[2].Value = returnData;
 }

AsParallel Method :

dataGrid1.Rows.Cast<DataGridViewRow>().AsParallel().ForAll(row =>
{
    // SOME CODES REMOVED FOR CLARITY
    string data1 = row.Cells[1].Value;
    var returnData = getHtml(data1);
    row.Cells[2].Value = returnData;
}); 

So, how can i use Parallel.ForEach loop with DataGridViewRow (DataGridView) ?

Thanks.

1 个答案:

答案 0 :(得分:4)

如果getHtml(以及你的循环的其他非UI部分)相对昂贵,那么做你想要并行做的事是有道理的,如果它便宜那么它没有意义并行执行,因为更新UI(您的数据网格)无论如何都需要是顺序的,因为只有UI线程可以更新它。

如果getHtml(以及循环的其他非UI部分)相对昂贵,您可以执行以下操作:

var current_synchronization_context = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() => //This is important to make sure that the UI thread can return immediately and then be able to process UI update requests
{
    Parallel.ForEach(dataGrid1.Rows.Cast<DataGridViewRow>(), row =>
    {
        // SOME CODES REMOVED FOR CLARITY
        string data1 = row.Cells[1].Value;
        var returnData = getHtml(data1); //expensive call

        Task.Factory.StartNew(() => row.Cells[2].Value = returnData,
            CancellationToken.None,
            TaskCreationOptions.None,
            current_synchronization_context); //This will request a UI update on the UI thread and return immediately
    }); 
});

创建Task并使用TaskScheduler.FromCurrentSynchronizationContext()将在Windows窗体应用程序和WPF应用程序中运行。

如果您不想为每个UI更新安排任务,可以直接调用BeginInvoke方法(如果这是一个Windows窗体应用程序),如下所示:

dataGrid1.BeginInvoke((Action)(() =>
{
    row.Cells[2].Value = returnData;
}));

我上面的建议会导致数据在处理/生成时呈现给用户界面。

如果您不关心这一点,并且您可以先处理所有数据然后更新UI,那么您可以执行以下操作:

1)从UI线程中的UI收集所有数据

2)通过Parallel.ForEach处理数据并将结果存储在数组

3)从UI线程

将数据渲染到UI