我知道没有必要等待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;
}
答案 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.For
或Task.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
如何将执行控制返回到消息循环然后继续当任务完成时,通过await
。 async-await
tag wiki可以提供帮助,它包含一些必读资源的链接。
如果您有兴趣了解阻止操作期间消息泵送的工作原理,请查看this answer。
答案 2 :(得分:1)
如果您想等待Parallel.For()
完成,您只是不能在单独的任务中启动它!
Parallel.For()
在完成之前不会返回(即使它使用多个线程来完成工作)。
请注意Parallel.For()
会返回ParallelLoopResult
- 它不会返回任务或其他任何可以让您等待它完成的内容,所以如果它确实在它完成之前返回(就像你一样)断言)没有办法知道它何时结束。