等待Parallel.For

时间:2014-02-10 15:29:02

标签: c# .net task-parallel-library

我知道没有必要等待Parallel.For,但由于在Parallel.For期间正在处理UI Windows消息(WinForms消息泵),我想等待Parallel.For完成。

Parallel.For封装在Task中是否是个好主意,然后等待它?有没有更好的方法?

感谢。

CancellationTokenSource token = new CancellationTokenSource();

const int len = 100;

double[] array = new double[len];

Task t = Task.Factory.StartNew(delegate {
   Parallel.For(0, len, delegate(int i, ParallelLoopState loopState) {

   array[i] += 1;

   });

try
{
   t.Wait(token.Token);
}
catch (OperationCanceledException e)
{
   rc = false;
}

3 个答案:

答案 0 :(得分:3)

而不是Parallel.For为什么不仅使用Task并致电Task.WaitAll()

var t1 = Task.Run(() => {});
var t2 = Task.Run(() => {});

Task.WaitAll(t1, t2);

答案 1 :(得分:3)

是什么让您确信WM_PAINT和其他Windows消息在Parallel.ForTask.Wait阻止UI线程时被抽取?

以下简单示例证明您错了。 <{1}}正在运行时,表格不会在整个15秒内重新绘制为红色。

Parallel.For

以下是如何在保持用户界面响应的同时并行运行任务:

using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WinFroms_21681229
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            this.Shown += MainForm_Shown;
        }

        void MainForm_Shown(object sender, EventArgs e)
        {
            MessageBox.Show("Before");

            this.BackColor = Color.FromName("red");
            this.Invalidate();

            // the form is not getting red for another 15 seconds
            var array = new double[] { 1, 2, 3 };
            Parallel.For(0, array.Length, (i) =>
            {
                System.Threading.Thread.Sleep(5000);
                Debug.Print("data: " + array[i]);
            });

            MessageBox.Show("After");
        }
    }
}

你可能已经完成了async void MainForm_Shown(object sender, EventArgs e) { MessageBox.Show("Before"); this.BackColor = Color.FromName("red"); this.Invalidate(); // the form is not getting red for another 15 seconds var array = new double[] { 1, 2, 4 }; var tasks = array.Select((n) => Task.Run(()=> { Thread.Sleep(5000); Debug.Print("data: " + n); })); await Task.WhenAll(tasks); MessageBox.Show("After"); } 这样的事情,但是至少会使用一个比真正需要的更多的线程。

要了解这里场景背后的情况,您需要了解WinForms消息循环如何在await Task.Factory.StartNew(() => Parallel.For(...))内工作,Application.Run如何将执行控制返回到消息循环然后继续当任务完成时,通过awaitasync-await tag wiki可以提供帮助,它包含一些必读资源的链接。

如果您有兴趣了解阻止操作期间消息泵送的工作原理,请查看this answer

答案 2 :(得分:1)

如果您想等待Parallel.For()完成,您只是不能在单独的任务中启动它!

Parallel.For()在完成之前不会返回(即使它使用多个线程来完成工作)。

请注意Parallel.For()会返回ParallelLoopResult - 它不会返回任务或其他任何可以让您等待它完成的内容,所以如果它确实在它完成之前返回(就像你一样)断言)没有办法知道它何时结束。