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

线程的一个好处是异步的执行操作,在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. 【VS开发】程序如何捕捉signal函数参数中指定的信号

    当说到signal的功能时,我们都知道它会捕捉我们所指定的信号,然后调用我们所指定的信号处理函数.但它是如何捕捉我们指定的信号的呢?下面我就以msdn上关于signal的example为例,说明sig ...

  2. Spring切面编程AOP

  3. linux 源码安装JAVA jdk

    下载Linux环境下的jdk1.8,请去(官网)中下载jdk的安装文件: 由于我的Linux是64位的,因此我下载jdk-8u131-linux-x64.tar.gz. 下载之后 解压命令进行解压 1 ...

  4. 如何使用C++实现单链表

    线性表--链表 为什么假期也在发文章 //TODO NullGirlfrindException 请忽略以上两行无聊的事实...... 如何弥补顺序表的不足之处? 第一次学习线性表一定会马上接触到一种 ...

  5. LeetCode 171. Excel表列序号(Excel Sheet Column Number) 22

    171. Excel表列序号 171. Excel Sheet Column Number 题目描述 给定一个 Excel 表格中的列名称,返回其相应的列序号. 每日一算法2019/5/25Day 2 ...

  6. LeetCode 189. 旋转数组(Rotate Array)

    189. 旋转数组 LeetCode189. Rotate Array 题目描述 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数. 示例 1: 输入: [1,2,3,4,5,6, ...

  7. Java设计模式:23种设计模式(转)

    单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式. 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多 ...

  8. Mybatis笔记2

    使用Mybatis完成的CRUD操作 个人总结的一些小规律 学习过程中碰到的错误: org.apache.ibatis.exceptions.PersistenceException: ### Err ...

  9. QT加载自带字体

    #include <QCoreApplication> #include <QStringList> #include <QFontDatabase> #inclu ...

  10. 使用vue和drf后台进行登录页面和注册页面(本文大概的疏通一下前后台是怎么交互的)

    注册页面 先从vue页面开始,下面是举例的vue页面截图 从上面的截图我们可以看到一些vue的指令:v-model和v-on(缩写成@) v-model是表单指令:就是获取属性值,在这里就是这些输入框 ...