浅谈.Net异步编程的前世今生----EAP篇

921fc7adb22d056ee56a1ef00d72c755.png

前言

1cf659b0727203456f51aca7aed2f752.png

在上一篇博文中,我们提到了APM模型实现异步编程的模式,通过使用APM模型,可以简化.Net中编写异步程序的方式,但APM模型本身依然存在一些缺点,如无法得知操作进度,不能取消异步操作等。

针对这些缺点,微软在.Net 2.0中提出了基于事件的异步模式,简称为EAP模型。

第二个异步编程模型:EAP

e363fb6bab261a4c4076996c136ce1dd.png

概述

684dadb48ff272ea6531fe014c8485ff.png

EAP,全称Event-based Asynchronous Pattern,基于事件的异步模式,它提供了一系列的事件声明与方法,用于实现异步模式的各个阶段。

典型的内置组件为BackgroundWorker组件,本文中我们将使用它来探寻此种模式的执行过程。

cc48d5edb8e9be9a6b695e55e2c4550d.png

使用

de33ad4dd24b35df6798070810bd0a9a.png

我们需要创建一个窗体应用,并模拟下载实时进度显示。创建WinForm后,放入Label控件用于展示下载进度和其他信息,并加入两个Button按钮,分别为开始下载和取消下载,再放入我们的主角:BackgroundWorker组件,如图所示:

6d7180d648c821af7563b109417e8d0f.png

在加入这些基本组件后,我们开始这一次的编码之旅,BackgroundWorker在后台属于一个类,因此它已经内置了部分属性和事件:

e883773e440b70f672f0cec864203a89.png

这些属性中包含取消、支持进度更新、判断是否执行等,恰恰是我们在这次异步操作中需要的。于是,我们根据需求编写了以下代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace BackgroundWorkerDemo
{public partial class BackgroundWorkerForm : Form{public BackgroundWorkerForm(){InitializeComponent();backgroundWorker1.WorkerReportsProgress = true;backgroundWorker1.WorkerSupportsCancellation = true;}/// <summary>/// 点击开始下载按钮/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnDownLoad_Click(object sender, EventArgs e){if (!backgroundWorker1.IsBusy) //判断是否正在执行异步操作{//backgroundWorker开始执行异步操作backgroundWorker1.RunWorkerAsync();}}/// <summary>/// 点击取消按钮/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void btnCancel_Click(object sender, EventArgs e){if (backgroundWorker1.WorkerSupportsCancellation) //判断是否支持异步取消操作{//开始执行取消操作backgroundWorker1.CancelAsync();}}/// <summary>/// backgroundworker异步执行事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e){System.ComponentModel.BackgroundWorker worker = sender as System.ComponentModel.BackgroundWorker;string msg = "当前线程是否为后台线程:" + Thread.CurrentThread.IsBackground + ",是否为线程池线程:" + Thread.CurrentThread.IsThreadPoolThread;WriteLog("Backgroundworker日志", msg);for (int i = 0; i < 20; i++){if (worker.CancellationPending){e.Cancel = true;break;}else{//模拟下载执行进度Thread.Sleep(500);worker.ReportProgress(i * 5);}}}/// <summary>/// 进度报告事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e){lblProcess.Text = "当前下载进度为:" + e.ProgressPercentage + "%,是否为后台线程:" + Thread.CurrentThread.IsBackground 
+ ",是否为线程池线程:" + Thread.CurrentThread.IsThreadPoolThread;}/// <summary>/// 异步操作完成事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){if (e.Cancelled) //此状态为取消{lblProcess.Text = "下载已经被取消";}else if (e.Error != null){lblProcess.Text = "出现错误:" + e.Error.Message;}else{lblProcess.Text = "下载已完成";}}/// <summary>/// 记录日志/// </summary>/// <param name="documentName"></param>/// <param name="msg"></param>public void WriteLog(string documentName, string msg){string errorLogFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log");if (!System.IO.Directory.Exists(errorLogFilePath)){System.IO.Directory.CreateDirectory(errorLogFilePath);}string logFile = System.IO.Path.Combine(errorLogFilePath, documentName + "@" + DateTime.Today.ToString("yyyy-MM-dd") + ".txt");bool writeBaseInfo = System.IO.File.Exists(logFile);StreamWriter swLogFile = new StreamWriter(logFile, true, Encoding.Unicode);swLogFile.WriteLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + msg);swLogFile.Close();swLogFile.Dispose();}  }
}

在这段示例代码中,我们首先设置组件支持取消及报告进度操作属性,其次在点击开始按钮时,判断是否执行,若未执行,则执行RunWorkerAsync方法,避免多次重复执行。

在EAP模型中,执行RunWorkerAsync方法后,会触发backgroundWorker1_DoWork事件。此事件中我们放入模拟实时下载进度代码,并调用ReportProgress进行进度报告,这时backgroundWorker1_ProgressChanged事件会被触发,同时对UI进行更新操作,此段过程运行结果如下图所示:

a2989caa059d06f135b3ba2fdf7e395e.png

82ba523d05dc41840da30701b9ba93c1.png

通过结果可以看出,运行过程中已经实现了实时更新进度的功能。与此同时,根据反馈的信息我们发现,backgroundWorker1_ProgressChanged事件内部是线程安全的,在操作UI时不会出现跨线程对UI进行更新的问题。

那么BackgroundWorker内部是不是依然使用了线程池及后台线程呢?我们来一起看看在backgroundWorker1_DoWork事件中记录的日志:

9a16e574bcd708acf079ac08b93db1e4.png

通过日志我们发现,EAP与APM一样,也使用了线程池中的线程,不得不感叹一句,线程池是个伟大的发明,微软真是无所不用其极啊!

讲到这里,细心的同学会发现,我们唠叨了这么半天,似乎还少了点什么,对了,取消操作,一起来看看效果:

45e34ecea5b355e8d72b59fb5acc299d.png

点击界面上的"取消下载"按钮后,会提示下载已经被取消。原因是我们在点击按钮时,首先判断了WorkerSupportsCancellation属性,看组件是否支持取消操作,随后执行CancelAsync方法进行异步取消。

由于这个过程是异步的,因此我们在backgroundWorker1_DoWork事件中不断判断CancellationPending属性,若取消则设置e.Cancel=true进行标志位标志,标志后我们可以在backgroundWorker1_RunWorkerCompleted判断是否已经取消,最后对UI进行提示输出,取消操作完成。

983318e7559af24726dd90640610af48.png

小结

86c7de25ea63fbd1d32a55745e263dd2.png

对比APM调用委托进行异步操作的方式,EAP显得更加简洁明了,只需更少的代码即可实现更多的功能。尤其是BackgroundWorker组件,定义相应的事件后,在不同阶段根据需求编写方法即可实现异步操作、报告进度及取消等。

但是EAP模型的使用,局限性会更强,主要包括以下几点:

  • 可用组件少,除了BackgroundWorker之外,仅有WebClient类支持此模型,在B/S程序中难以使用。

  • 只能使用预定义事件,无法手动定义回调函数,且依赖事件的执行顺序。

  •   内部封装较多,占用资源比APM方式多。

因此在愈演愈烈的需求中,微软又对异步编程模型进行了变革,一种兼顾强大与灵活的新模型诞生了,它会是谁呢?预知后事如何,且听下回分解。

f506143509c332dc3a906ef75f6bd22c.png

您的点赞和在看是我创作的最大动力,感谢支持

af3799100faf2b121656d43a9992fff4.png

1cb98837f093b489ef267ace31b2e516.png

83ef3463b99cb66136037078334d6219.png

公众号:wacky的碎碎念

知乎:wacky

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS 5 CentOS 6 启动流程及关键步骤

CentOS 5 CentOS 6 启动流程及关键步骤1、加电自检&#xff1a;当打开主机电源时&#xff0c;主机会唤醒cpu&#xff0c;使其运行CMOS中的BIOS&#xff0c;BIOS检查必要的硬件是否存在&#xff08;内存、硬盘等&#xff09;BIOS其实是一个小型系统&#xff0c;可以完成一些像检…

建议给予导师决定硕博士能否毕业的自主权?教育部:将充分采纳!

全世界只有3.14 % 的人关注了爆炸吧知识本文来源&#xff1a;教育部 近日&#xff0c;教育部官网公布了《对十三届全国人大三次会议第9546号建议的答复》。针对人大代表提出的关于完善高校研究生科研成果评价标准的建议&#xff0c;教育部作出回应&#xff0c;并透露了对加强研…

浅谈.Net异步编程的前世今生----APM篇

前言在.Net程序开发过程中&#xff0c;我们经常会遇到如下场景&#xff1a;编写WinForm程序客户端&#xff0c;需要查询数据库获取数据&#xff0c;于是我们根据需求写好了代码后&#xff0c;点击查询&#xff0c;发现界面卡死&#xff0c;无法响应。经过调试&#xff0c;发现查…

浅谈.Net异步编程的前世今生----TPL篇

前言我们在此前已经介绍了APM模型和EAP模型&#xff0c;以及它们的优缺点。在EAP模型中&#xff0c;可以实时得知异步操作的进度&#xff0c;以及支持取消操作。但是组合多个异步操作仍需大量工作&#xff0c;编写大量代码方可完成。因此&#xff0c;在.Net Framework 4.0中&am…

Google:推荐几款好用的Chrome浏览器插件

1、Clear Cache 0.3.3.2 一键清空浏览器缓存数据。 https://chrome.google.com/webstore/detail/clear-cache/cppjkneekbjaeellbfkmgnhonkkjfpdn 2、Pig Toolbox 1.0.6.4 双击关闭页签&#xff0c;鼠标手势&#xff0c;手势动作轮&#xff0c;摇臂&#xff0c;超级拖拽&#xf…

豆瓣8.7!BBC这部成人社会禁片,曝光了行业内不能说的秘密

全世界只有3.14 % 的人关注了爆炸吧知识不知道生活中的你是否也会这样&#xff1f;平时即便不买东西&#xff0c;没事也会打开淘宝看看。但凡遇上双11、618各种促销节&#xff0c;总觉得不买好像就亏了&#xff0c;每每忍不住手痒&#xff0c;交了一堆智商税之后又开始后悔。如…

Lync-用户-电话号码-更新

1. 更新-用户-手机号 2. 服务器-更新-地址簿 3. 客户端-更改-注册表-<只操作一次!> 在命令提示符中输入如下命令&#xff1a; Reg Add HKLM\Software\Policies\Microsoft\Communicator /v GalDownloadInitialDelay /t REG_DWORD /d 0 /f 4. 客户端-删除-用户信息 退出-Ly…

豆瓣评分9分+,6部经典趣味数学纪录片!

全世界只有3.14 % 的人关注了爆炸吧知识数学是研究数量、结构、变化以及空间模型等概念的一门学科。透过抽象化和逻辑推理的使用&#xff0c;由计数、计算、量度和对物体形状及运动的观察中产生。数学家们拓展这些概念&#xff0c;为了公式化新的猜想以及从合适选定的公理及定义…

C# Hook原理及EasyHook简易教程

前言在说C# Hook之前&#xff0c;我们先来说说什么是Hook技术。相信大家都接触过外挂&#xff0c;不管是修改游戏客户端的也好&#xff0c;盗取密码的也罢&#xff0c;它们都是如何实现的呢&#xff1f;实际上&#xff0c;Windows平台是基于事件驱动机制的&#xff0c;整个系统…

squid 服务器的应用

实验名称&#xff1a;squid 服务器的应用 实验目标&#xff1a; 任务一&#xff1a;实现正向代理 任务二&#xff1a;实现透明代理 任务三&#xff1a;实现反向代理 提示1、在启动squid服务程序之前需要先确认Linux主机具有完整的域名&#xff0c;如果没有可以在hosts文件中进行…

有的人走着走着就散了!

1 有的人走着走着就走了上坡路▼2 没有感情的甩绳机器▼3 大男孩们陪小朋友踢球到底谁玩的比较开心▼4 给我妈妈演示一下我在肚子里的时候是怎么踹你的▼5 狗子&#xff1a;谢谢您嘞&#xff0c;我这是耳朵不是抹布&#xff01;▼6 从没想到会在这种情况下和你相遇▼7 所…

官宣 .NET 6 RC (Release Candidate) 2

我们很高兴发布 .NET 6 RC(Release Candidate) 2。它是生产环境中支持的两个“go live”候选版本中的第二个。在过去的几个月里&#xff0c;团队一直专注于质量的改进。这个版本中有很多的新特性&#xff0c;但在接近尾声时我们才会把他们完全整合在一起。该团队目前正在验证端…

SQL Server索引进阶第十篇:索引的内部结构

索引设计是数据库设计中比较重要的一个环节&#xff0c;对数据库的性能其中至关重要的作用&#xff0c;但是索引的设计却又不是那么容易的事情&#xff0c;性能也不是那么轻易就获取到的&#xff0c;很多的技术人员因为不恰当的创建索引&#xff0c;最后使得其效果适得其反&…

JDK安装及java环境配置_JDK安装及Java环境变量配置

2.点击Accept License Agreement&#xff0c;下载适合自己电脑版本的JDK.由于我的电脑是windows10 64位专业版。点击红色下载按钮。保存位置自己决定&#xff0c;只要自己安装时能找到就行。3.找到安装文件&#xff0c;双击。4.下一步&#xff0c;这里会让你选择安装目录。注意…

33张你没看过的酷炫化学动图, 秒懂化学反应原理!

化学的神奇魅力可是不是随便说说的&#xff0c;神奇起来让人叹为观止。下面就让腾远君带领大家看看传说中的37张神图&#xff0c;了解化学之美吧。1 . 硫氰酸汞分解&#xff08;“法老之蛇”&#xff09;原理&#xff1a;硫氰酸汞受热分解&#xff0c;部分产物燃烧。2Hg(SCN)2→…

从编译器层面理解C#中的闭包的这个坑!

前言在公众号上看到一篇文章《正确使用和理解C#中的闭包》&#xff0c;里面提到了闭包的一个坑&#xff1a;当捕获的外部变量为for循环的迭代变量时&#xff0c;C#认为变量i是定义在循环体外的。所以&#xff0c;当添加委托集合的for循环执行完时&#xff0c;i的值已经变为3了&…

C# 使用 HelpProvider 控件调用帮助文件

HelpProvider控件可以将帮助文件(.htm文件或.chm文件)与 Windows 应用程序相关联&#xff0c;为特定对话框或对话框中的特定控件提供区分上下文的帮助&#xff0c;打开帮助文件到特定部分。如目录、索引或搜索功能的主页。如图1 所示为 HelpProvider 控件。图1 HelpProvider…

哈哈哈,弟弟被卡桶里了......

1 哈哈哈哈哈弟弟被卡桶里面了&#xff08;via.小妮&#xff09;&#xff08;注意安全&#xff0c;请勿模仿&#xff01;&#xff09;▼2 弟弟是个狠人▼3 Self-potato: 一种不需要沙发也能无意义地待着的生活方式&#xff08;via.字幕少女&#xff09;▼4 防晒的正确打开方…

LVM基本应用 扩展及缩减实现

LVM: Logical Volume Manage首先&#xff1b;pv管理工具&#xff1a; pvs&#xff1a;简要pv信息显示 pvdisplay&#xff1a;显示pv的详细信息pvcreate /dev/DEVICE: 创建pvvg管理工具&#xff1a; vgs vgdisplayvgcreate [-s #[kKmMgGtTpPeE]] VolumeGroupName Physical…

java 线程 插件_我的第一个Chrome插件:天气预报应用

1.Chrome插件开发基础开发Chrome插件很简单&#xff0c;只要会基本的前台技术HTML、CSS、JS就可以开发了。Chrome插件一般包括两个HTML页面background和popup。background页面只在启动浏览器加载插件时载入一次&#xff0c;它不直接显示出来而是在后台运行。它包含了插件的主要…