我知道不需要等待Parallel.For,但由于UI消息(WinForms消息泵)在Parallel.For期间正在处理,所以我希望等待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;
}发布于 2014-02-10 23:30:47
为什么不直接使用Task并调用Task.WaitAll()而不是Parallel.For
var t1 = Task.Run(() => {});
var t2 = Task.Run(() => {});
Task.WaitAll(t1, t2);发布于 2014-02-10 23:31:30
如果你想等待一个Parallel.For()完成,你不需要在一个单独的任务中启动它!
Parallel.For()直到完成才会返回(即使它使用多个线程来完成这项工作)。
请注意,Parallel.For()返回一个ParallelLoopResult -它不返回任务或任何其他允许您等待它完成的内容,所以如果它在完成之前返回(如您所断言的),将无法知道它何时完成。
发布于 2014-02-11 09:36:47
当Parallel.For或Task.Wait阻塞在UI线程上时,是什么让您如此确信WM_PAINT和其他Windows消息会被释放?
下面这个简单的例子证明你错了。在Parallel.For工作的整个15秒内,窗体都不会被重新绘制为红色。
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");
}
}
}这里介绍了如何在保持UI响应的同时并行运行任务:
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");
}你可以做一些像await Task.Factory.StartNew(() => Parallel.For(...))这样的事情,但是这至少会比实际需要多使用一个线程。
要理解这里幕后发生的事情,您需要了解WinForms消息循环在Application.Run中是如何工作的,await如何将执行控制权交还给消息循环,然后在任务完成时通过WindowsFormsSynchronizationContext继续执行。async-await tag wiki可以提供帮助,它包含一些很棒的、必读的资源的链接。
如果您有兴趣了解消息泵在阻塞操作期间是如何工作的,请查看this answer。
https://stackoverflow.com/questions/21681229
复制相似问题