取消长时间操作的最佳方法是什么?
我遇到了一个我不确定如何解决的问题。 我有一个方法,其中包含来自填充数据表的服务的调用,例如:
private void GetCases()
{
try
{
//Setup our criteria
Web_search_criteria myCriteria = new Web_search_criteria()
{
Keynum = 9, //Use Opening Date Key
Range_start = "20100101", //01-01-2010
Range_end = "20121223" //12-23-2013
};
//The myCases object is a datatable that is populated from the GetCasesDT() call.
int status = db.server.GetCasesDT(myCriteria, ref myCases);
}
catch (Exception ex)
{
XtraMessageBox.Show("Unable to get data: " + ex.Message);
}
}
所以,正如你所看到的,我没有办法一次抓住几个案例 - 它只是抓住了一切。
现在,我在BackgroundWorker的DoWork事件中调用了此方法,并且我在其上显示了另一个带有滚轮进度条的表单,以便用户知道系统实际上正在执行某些操作。 在该表单上,我有一个我订阅的取消按钮。 下面是这样做的代码:
backgroundWorker1 = new BackgroundWorker()
{
WorkerSupportsCancellation = true,
WorkerReportsProgress = true
};
//DoWork Event
backgroundWorker1.DoWork += backgroundWorker1_DoWork;
//Show the progress bar with subscription to event
pb.btnCancel.Click += this.CancelBW;
pb.Show();
//Run the backgroundworker
this.backgroundWorker1.RunWorkerAsync();
//Don't lock up the application
while (this.backgroundWorker1.IsBusy)
{
Application.DoEvents();
}
我试图通过使用CancelAsync()来取消CancelBW事件中的BackgroundWorker,但后来我阅读了更多内容并意识到这种方式不起作用,并且只有在我可以分解该初始呼叫以便BackgroundWorker可以检查进度时才会起作用。
我曾考虑过使用Thread而不是BackgroundWorker,但已经读过,放弃一个线程会导致小猫自发地燃烧。
那么,对于我来说,处理这种用户可以取消一个漫长过程的最佳方式是什么?
没有根本的方法来正确取消此操作。 这不是CPU绑定的工作,它是网络绑定的工作。 你发送了这个请求,你不能从互联网上准确地采集这个请求。 你所能做的只是在满足取消条件时继续执行代码,而不是等待操作完成。
您的应用程序的一个主要问题是您抽取消息队列的busyloop:
while (this.backgroundWorker1.IsBusy)
{
Application.DoEvents();
}
这通常是一个坏主意,而且应该避免这种做法。 首先使用BackgroundWorker
的想法是它是异步的; 在BGW完成之前,您不应该试图阻止当前的方法。
虽然有办法将BGW纳入其中; 这个特殊情况可能更容易使用任务并行库来解决。
var cts = new CancellationTokenSource();
pb.btnCancel.Click += (s, e) => cts.Cancel();
pb.Show();
var task = Task.Factory.StartNew(() => GetCases())
.ContinueWith(t => t.Result, cts.Token)
.ContinueWith(t =>
{
//TODO do whatever you want after the operation finishes or is cancelled;
//use t.IsCanceled to see if it was canceled or not.
});
(我还建议重构GetCases
以便它返回从数据库中获取的DataTable
,而不是修改实例字段,然后可以通过任务Result
访问它。
如果你不想放弃线程(这实际上会导致世界崩溃并且小猫在燃烧),结束一个线程的唯一理智的方法是对其内部的工作进行细化,并且对取消标记进行频繁检查(在任何情况下形式上你更喜欢他们:内置于[对于TPL],消息,锁定变量,信号量或其他),并以“干净地”结束线程。
链接地址: http://www.djcxy.com/p/18095.html