当前位置: 首页 > news >正文

深入浅出多线程系列之六:事件驱动异步模式(EAP,WebClient,BackgroundWorker)

Event-based asynchronous(EAP)在多线程的环境中提供了一个简单的处理方式。

它有以下几个特性:

 

  1. 支持取消。
  2. 可以安全的更新WPFwindows Forms 控件。
  3. completion event中可以查询异常信息。
  4. “在后台”执行耗时任务(例如下载和数据库操作),但不会中断您的应用程序。

  5. 同时执行多个操作,每个操作完成时都会接到通知。

  6. 等待资源变得可用,但不会停止(“挂起”)您的应用程序。

  7. 使用熟悉的事件和委托模型与挂起的异步操作通信。 

EAP仅仅只是一个模式而已。,所以这些特性必须都由实现者来实现。在Framework中有少数几个类支持这种模式,最著名的就是BackgroundWorkerSystem.Net.WebClient 了。

这个模式的本质是:每个类都提供了一些相似的成员来管理多线程,例如:

 

public byte[] DownloadData(Uri address);

public void DownloadDataAsync(Uri address);

public void DownloadDataAsync(Uri address, object userToken);

public event DownloadDataCompletedEventHandler DownloadDataCompleted;

 

public void CancelAsync(); //取消操作

public bool IsBusy { get; } //获取是否正在运行的信息。

 

下面是使用WebClient 的例子:

复制代码
var wc  =   new  WebClient();
            wc.DownloadStringCompleted 
+=  (sender, args)  =>
                {
                    
if  (args.Cancelled)
                        Console.WriteLine(
" Canceled " );
                    
else   if  (args.Error  !=   null )
                        Console.WriteLine(
" Exception: "   +  args.Error.Message);
                    
else
                    {
                        Console.WriteLine(args.Result.Length 
+   "  chars were downloaded " );
                    }
                };
            wc.DownloadStringAsync(
new  Uri( " http://www.cnblogs.com/LoveJenny/ " ));
复制代码

 

一个WebClient虽然有多个异步方法,但是因为它们都共享了相同的CancelAsync IsBusy属性,所以一次只能有一个异步操作。

 

BackgroundWorker

BackgroundWorkerSystem.ComponentModel下面的一个管理工作线程的帮助类,提供了下面几个特性

  1. 支持取消。
  2. 可以安全的更新WPFwindows Forms 控件。
  3. completion event中可以查询异常信息。
  4. 可以报告进度。
  5. 因为实现了IComponent接口,所以可以被设计器使用。
  6. BackgroundWorker使用了线程池,这意味着你永远都不能在一个BackgroundWorker线程上调用Abort方法
复制代码
static  BackgroundWorker _bw  =   new  BackgroundWorker();

        
public   static   void  MainThread()
        {
            _bw.DoWork 
+=   new  DoWorkEventHandler(_bw_DoWork);
            _bw.RunWorkerAsync(
" Message to worker " );
            Console.ReadLine();
        }

        
static   void  _bw_DoWork( object  sender, DoWorkEventArgs e)
        {
            Console.WriteLine(e.Argument);
            
// 做一些耗时的操作。
        }
复制代码

 

下面的例子实现了进度报告。

复制代码
class  ThreadBackgroundWorker
    {
        
static  BackgroundWorker _bw;

        
public   static   void  MainThread()
        {
            _bw 
=   new  BackgroundWorker
            {
                WorkerReportsProgress 
=   true ,   // 允许报告进度
                WorkerSupportsCancellation  =   true    // 允许取消
            };

            _bw.DoWork 
+=   new  DoWorkEventHandler(_bw_DoWork);
            _bw.ProgressChanged 
+=   new  ProgressChangedEventHandler(_bw_ProgressChanged);
            _bw.RunWorkerCompleted 
+=   new  RunWorkerCompletedEventHandler(_bw_RunWorkerCompleted);

            _bw.RunWorkerAsync(
" Hello to worker " );
            Console.WriteLine(
" Press Enter in the next 5 seconds to cancel. " );
            Console.ReadLine();
            
            
if  (_bw.IsBusy) _bw.CancelAsync();
            Console.ReadLine();
        }

        
static   void  _bw_RunWorkerCompleted( object  sender, RunWorkerCompletedEventArgs e)
        {
            
if  (e.Cancelled)        // 是否取消
                Console.WriteLine( " You canceled! " );
            
else   if  (e.Error  !=   null )   // 是否有异常
                Console.WriteLine( " Worker exception: "   +  e.Error.ToString());
            
else
                Console.WriteLine(
" Complete: "   +  e.Result);
        }

        
static   void  _bw_ProgressChanged( object  sender, ProgressChangedEventArgs e)
        {
          
// 输出进度报告
            Console.WriteLine( " Reached  "   +  e.ProgressPercentage  +   " % " );
        }

        
static   void  _bw_DoWork( object  sender, DoWorkEventArgs e)
        {
            
for  ( int  i  =   0 ; i  <=   100 ; i  +=   20 )
            {
                
if  (_bw.CancellationPending) { e.Cancel  =   true return ; }
                _bw.ReportProgress(i);   
// 报告进度
                Thread.Sleep( 1000 );
            }

            e.Result 
=   123 ;
        }
    }
复制代码

 

 






本文转自LoveJenny博客园博客,原文链接:http://www.cnblogs.com/LoveJenny/archive/2011/05/25/2053688.html,如需转载请自行联系原作者

相关文章:

  • 小本领: 一条下令装配 Firefox 3 Beta 3
  • 因子得分
  • 红旗桌面版本最新使用要领和标题解答100例-1
  • nginx 1.8.1安装使用
  • 利用Travis CI 让你的github项目持续构建(Node.js为例)
  • XP组件下看不到IIS
  • 一个绿色版的正则表达式测试工具
  • Git学习笔记(一)
  • C++ STL速查手册笔记
  • Flickr 网站架构分析
  • SEO终极算法(二)
  • 内容超出表格td宽度则自动隐藏
  • 用jk整合Apache和tomcat实现负载均衡
  • 处理不完整数据集
  • BMP位图格式详解一--转载
  • 2017-08-04 前端日报
  • 2018一半小结一波
  • 5、React组件事件详解
  • C++类中的特殊成员函数
  • Codepen 每日精选(2018-3-25)
  • JSDuck 与 AngularJS 融合技巧
  • Nacos系列:Nacos的Java SDK使用
  • QQ浏览器x5内核的兼容性问题
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • sessionStorage和localStorage
  • SpiderData 2019年2月23日 DApp数据排行榜
  • underscore源码剖析之整体架构
  • webgl (原生)基础入门指南【一】
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 和 || 运算
  • 两列自适应布局方案整理
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 网络应用优化——时延与带宽
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • #Linux(权限管理)
  • #QT(一种朴素的计算器实现方法)
  • (04)odoo视图操作
  • (13)Hive调优——动态分区导致的小文件问题
  • (LeetCode 49)Anagrams
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (分类)KNN算法- 参数调优
  • (转)程序员技术练级攻略
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • @transactional 方法执行完再commit_当@Transactional遇到@CacheEvict,你的代码是不是有bug!...
  • [android学习笔记]学习jni编程
  • [BZOJ 1032][JSOI2007]祖码Zuma(区间Dp)
  • [C++] 统计程序耗时
  • [CC2642r1] ble5 stacks 蓝牙协议栈 介绍和理解
  • [CSS]中子元素在父元素中居中
  • [J2ME]如何替换Google Map静态地图自带的Marker
  • [LeetCode 687]最长同值路径
  • [LeetCode]: 145: Binary Tree Postorder Traversal