这个初步问题还有一个更新
我有一个查询,可以提取大约90,000个 Headers 记录 . 然后我想遍历该结果集以获取检索到的每个头的详细数据 . 如果我线性处理它需要将近一个半小时 . 如果我将它并行化,我可以在11分钟内完成它 . 但是,没有屏幕更新 . 我已经做了很多次多线程应用程序,并且总是成功地执行以下操作:
this.lblStatus.Invoke(new MethodInvoker(() => this.lblStatus.Text = "Updating Standards Docs"));
但是,这似乎真的屏蔽了一个并行循环 . 使用该方法进行某些屏幕更新,并行循环从未实际完成 . 所以我需要另一种方法 .
我一直在努力:
Task.Factory.StartNew(() =>
{
OrderablePartitioner partitioner = Partitioner.Create(query, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, thisCheck =>
{
Interlocked.Increment(ref iChckNo);
lock (_status)
{
_status.ProcessMsg = "Voucher " + thisCheck.VoucherNumber;
_status.ProcessName = thisCheck.EmployeeName;
_status.CurrentRec = iChckNo;
dtSpan = DateTime.Now.Subtract(dtSpanStart);
_status.TimeMsg = string.Format("Elapsed {0}:{1}:{2}", dtSpan.Hours, dtSpan.Minutes, dtSpan.Seconds);
}
BeginInvoke((Action) (() =>
{
lblVoucher.Text = _status.ProcessMsg;
lblName.Text = _status.ProcessName;
lblCount.Text = string.Format("Record {0} of {1}", _status.CurrentRec, _status.TotalRecs);
lblTime.Text = _status.TimeMsg;
Application.DoEvents();
}));
thisCheck.GetDetails();
});
}).Wait();
任务上的等待是因为之后我需要对查询执行其他操作,最后我会将其放入ContinueWith语句中,我真的需要让屏幕更新起作用 .
我知道所有关于跨线程损坏的原因,这就是我尝试使用Invoker方法的原因......我坚信长时间运行的进程仍然需要让用户知情,这就是我尝试这个的原因 .
顺便说一句,它是一个WinForms应用程序,而不是WPF应用程序 . 任何帮助都将非常感谢...
更新:所以有人想看到更新的代码,IProgress进入它 .
Status _status = new Status {TotalRecs = query.Count};
var progress = new Progress(msg => WriteStatusUpdate(msg));
Task.Run(() =>
{
OrderablePartitioner partitioner = Partitioner.Create(query, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, thisCheck =>
{
lock (_status)
{
_status.ProcessMsg = "Voucher " + thisCheck.VoucherNumber;
_status.ProcessName = thisCheck.EmployeeName;
_status.CurrentRec = ++iChckNo;
dtSpan = DateTime.Now.Subtract(dtSpanStart);
_status.TimeMsg = string.Format("Elapsed {0}:{1}:{2}", dtSpan.Hours, dtSpan.Minutes, dtSpan.Seconds);
}
((IProgress) progress).Report(_status);
thisCheck.GetDetails();
});
}).Wait();
private void WriteStatusUpdate(Status _status)
{
lblVoucher.Text = _status.ProcessMsg;
lblVoucher.Refresh();
lblName.Text = _status.ProcessName;
lblName.Refresh();
lblCount.Text = string.Format("Records {0} of {1}", _status.CurrentRec, _status.TotalRecs);
lblCount.Refresh();
lblTime.Text = _status.TimeMsg;
lblTime.Refresh();
}
更新屏幕的代码永远不会被调用...