边学习边分享,纯属抛砖引玉。

线程的一个好处是异步的执行操作,在winform中,很多耗时操作执行时,为优化用户体验,避免长时间等待,从而运用线程技术异步的执行耗时操作,但不会阻塞主线程。

最近系统很多耗时查询导致体验很差,于是想到了用BackGroundWorker异步处理。而且要支持某些耗时达到几十秒的操作,可以取消。

BackGroundWorker有CancelAsync()这个方法。该方法只会将BackGroundWorker的CancellationPending属性设为true,但不会实际终止线程!网上找了些资料,代码如下

  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{ for (int i = ; i < ; i++)
{
if (backgroundWorker1.CancellationPending) {
e.Cancel = true;
return;
}
}
}

即在doWork事件中,不停的循环判断是否执行了取消操作。这种适用于执行多次方法时,而且无法在某个方法执行时将线程取消。如果我doWork事件里,没有for循环,而是一次耗时的数据访问操作,那这样的处理没有任何意义。

于是在下想到,可以在doWork事件里做如下处理

1.异步的去执行耗时操作。

2.while监视异步耗时操作是否完成,只要未完成就一直循环。循环内部判断是否执行了取消操作。如果执行了取消操作,则终止线程。代码如下

       private delegate int LongTimeDele();
private bool isComplated=false;
private int result=;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.BeginInvoke(new LongTimeDele(()=>{
Thread.Sleep();////模拟耗时
for (int i = ; i < ; i++)
{
result++;
}
isComplated=true;
})); while(!isComplated){ if (backgroundWorker1.CancellationPending) {
e.Cancel = true;
return;
}
}
}

试验之后,不知何故在this.BeginInvoke中的循环会阻塞主线程! 即界面卡主不动了,BeginInvoke应该是一步执行的,在下功力尚浅,不知何故,还请高手指教。

于是想到了异步委托。直接上代码

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();
var sumResult = ;
for (int i = ; i < ; 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();
}
}

异步委托方式取消BackGroundWorker执行无循环的耗时方法的更多相关文章

  1. 使用getScript()方法异步加载并执行js文件

    使用getScript()方法异步加载并执行js文件 使用getScript()方法异步请求并执行服务器中的JavaScript格式的文件,它的调用格式如下所示: jQuery.getScript(u ...

  2. iOS 设置 延迟执行 与 取消延迟执行 方法 以及对 run loop 初步认识

    之前开发过程中经常会有需求会使用 NSObject中的"performSelector:withObject:afterDelay:"做方法延迟执行的处理, 但是 还没有什么地方需 ...

  3. C# 如何取消BackgroundWorker异步操作

    BackgroundWorker 在执行DoWork事件时该如何取消呢? 方法1 DoWork 执行一个(耗时)循环 方法2 DoWork执行一个(耗时)方法[注:方法没有循环] 见代码: 方法1中D ...

  4. 在Winform开发中,使用Async-Awati异步任务处理代替BackgroundWorker

    在Winform开发中有时候我们为了不影响主UI线程的处理,以前我们使用后台线程BackgroundWorker来处理一些任务操作,不过随着异步处理提供的便利性,我们可以使用Async-Awati异步 ...

  5. js同步、异步、回调的执行顺序以及闭包的理解

    首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...

  6. LazyMay:实现同步和异步任务的顺序执行

    在掘金看到的文章,流程控制同步和异步任务的顺序执行,收益匪浅,工作中能用到. 1.实现以下效果 实现一个LazyMan,可以按照以下方式调用: LazyMan(“Hank”)输出: Hi! This ...

  7. js的for循环中出现异步函数,回调引用的循环值始终是最后的值

    一.问题 今天工作中解决bug发现是由“for循环的异步函数,回调引用的循环值始终是最后的值”的现象导致的,如: for (var i = 0; i < files.length; i++) { ...

  8. 矩阵之间无循环计算L2距离

    实现两个矩阵的无循环计算欧氏距离 Euclidean distance navigation: 1.问题描述 2.解决方法 1.问题来源 kNN算法中会计算两个矩阵的距离 可以使用循环的方法来实现,效 ...

  9. 异步委托(APM)使用Func异步操作,处理耗时操作

    使用委托进行异步操作,处理一些耗时操作,防止主线程阻塞 使用例子: using System; using System.Collections.Generic; using System.Linq; ...

随机推荐

  1. GATK4注意事项

    近期在测试多样品的WES的过程中发现用HC得到gvcf之后,合并多个样品的gvcf文件的过程中,使用CombineGVCFs的过程中很慢,发现官网推荐使用GenomicsDBImport 用法如下: ...

  2. 032 Android Service

    1.介绍 2.新建Service (1) (2)在Androidmanifest.xml文件中配置service <service android:name=".Myservice&q ...

  3. [PDF] - 获取 RadioButtonList 控件值的方法

    背景 目标是通过 iTextSharp 读取 PDF 模板,填充内容后以生成新 PDF 文件.利用 福昕PDF编辑器个人版 可以获取到 RadioButtonList 的组名,但是获取不到每一个 Ra ...

  4. python基础学习(十一)

    22.类 # 类 class # 实例 实体 instance class Student: # 空语句 保持结构的完整性 pass jack = Student() jack.name = &quo ...

  5. 创建线程的三种方式(Thread、Runnable、Callable)

    方式一:继承Thread类实现多线程: 1. 在Java中负责实现线程功能的类是java.lang.Thread 类. 2. 可以通过创建 Thread的实例来创建新的线程. 3. 每个线程都是通过某 ...

  6. oracle安装内核参数设置

    安装oracle内核参数说明及设置 kernel.shmmax 说明: Linux进程可以分配的单独共享内存段的最大值(byte) 64位的linux操作系统,设置应该大于SGA_MAX_TARGET ...

  7. Python进阶: Decorator 装饰器你太美

    函数 -> 装饰器 函数的4个核心概念 1.函数可以赋与变量 def func(message): print('Got a message: {}'.format(message)) send ...

  8. vue 写一个瀑布流插件

    效果如图所示: 采用了预先加载图片,再计算高度的办法..网络差的情况下,可能有点卡 新建 vue-water-easy.vue  组件文件 <template> <div class ...

  9. Spring Cloud Alibaba学习笔记(9) - RocketMQ安装与RocketMQ控制台

    搭建RocketMQ 系统环境准备 64位操作系统,推荐使用Linux.Unix.MacOS 64位 JDK1.8+ Maven 3.2.x 适用于Broker服务器的4g +可用磁盘 下载与搭建 下 ...

  10. go的安装及环境变量设置

    1,go安装 https://studygolang.com/dl 官网下载,找自己需要的版本,傻瓜式安装 2.go的环境变量设置 windows下面要设置root和path root代表go安装路径 ...