边学习边分享,纯属抛砖引玉。异步
线程的一个好处是异步的执行操做,在winform中,不少耗时操做执行时,为优化用户体验,避免长时间等待,从而运用线程技术异步的执行耗时操做,但不会阻塞主线程。学习
最近系统不少耗时查询致使体验不好,因而想到了用BackGroundWorker异步处理。并且要支持某些耗时达到几十秒的操做,能够取消。优化
BackGroundWorker有CancelAsync()这个方法。该方法只会将BackGroundWorker的CancellationPending属性设为true,但不会实际终止线程!网上找了些资料,代码以下this
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { for (int i = 0; i < 100; i++) { if (backgroundWorker1.CancellationPending) { e.Cancel = true; return; } } }
即在doWork事件中,不停的循环判断是否执行了取消操做。这种适用于执行屡次方法时,并且没法在某个方法执行时将线程取消。若是我doWork事件里,没有for循环,而是一次耗时的数据访问操做,那这样的处理没有任何意义。spa
因而在下想到,能够在doWork事件里作以下处理线程
1.异步的去执行耗时操做。code
2.while监视异步耗时操做是否完成,只要未完成就一直循环。循环内部判断是否执行了取消操做。若是执行了取消操做,则终止线程。代码以下orm
private delegate int LongTimeDele(); private bool isComplated=false; private int result=0; private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { this.BeginInvoke(new LongTimeDele(()=>{ Thread.Sleep(10000);////模拟耗时 for (int i = 0; i < 100; i++) { result++; } isComplated=true; })); while(!isComplated){ if (backgroundWorker1.CancellationPending) { e.Cancel = true; return; } } }
试验以后,不知何故在this.BeginInvoke中的循环会阻塞主线程! 即界面卡主不动了,BeginInvoke应该是一步执行的,在下功力尚浅,不知何故,还请高手指教。blog
因而想到了异步委托。直接上代码事件
cs代码
public partial class BackgroundWorkerTest : Form { public BackgroundWorkerTest() { InitializeComponent(); } /// <summary> /// 创建一个委托,用来调用耗时操做。返回值是int,固然也能够是string、DataTable..... /// </summary> /// <returns></returns> private delegate int LongTimeDele(); /// <summary> /// doWork事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { //声明一个委托的实例 var waitHandller = new LongTimeDele( () => { //线程休眠10秒,模拟耗时操做 Thread.Sleep(10000); var sumResult = 0; for (int i = 0; i < 100; i++) { sumResult++; } return sumResult; }); //BeginInvoke,异步的去执行委托实例里的匿名方法。该方法返回的是一个IAsyncResult。返回值的状态会实时更新! var isa = waitHandller.BeginInvoke(null, null); //因为上面是异步,因此while的代码不会等待上面操做完成后执行,两者几乎同时执行 //判断isa是否完成了,未完成的话(等待耗时操做)执行内部代码 while (!isa.IsCompleted) { //判断CancellationPending属性是否为true。若是你点击了取消button,这个属性就变成true了 if (backgroundWorker1.CancellationPending) { //取消操做 e.Cancel = true; return; } } //能执行到这里就说明操做完成了,把结果放进e中,传递给RunWorkerCompleted事件 e.Result = waitHandller.EndInvoke(isa); } /// <summary> /// backgroundWorker执行完毕时事件,不管正常完成仍是取消都会出发该事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //只要不是类型EventArgs,你想要的数据e里面应有尽有!判断是否取消了操做 if (e.Cancelled) { MessageBox.Show("操做已取消"); return; } //不然显示结果 MessageBox.Show(e.Result.ToString()); } /// <summary> /// 取消按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnCancle_Click(object sender, EventArgs e) { //调用 backgroundWorker的CancelAsync()方法,该方法只会将CancellationPending属性设为true,并不会实际结束线程执行 backgroundWorker1.CancelAsync(); } /// <summary> /// 开始按钮事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStart_Click(object sender, EventArgs e) { //判断线程是否繁忙 if (backgroundWorker1.IsBusy) { MessageBox.Show("系统繁忙"); return; } //空闲开始异步操做 backgroundWorker1.RunWorkerAsync(); } }