摘要

异步这东西,真正用起来的时候,发现事情还是挺多的,最近在项目中用到了异步的知识,发现对它还是不了解,处理起来,走了不少弯路。觉得还是补一补还是很有必要的。

MSDN原文地址:https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx

正文

.Net framework可以让你异步调用任何方法。为达这样的目的,你可以定义一个与你要调用的方法的签名相同的委托。公共语言运行时将自动为该委托定义与签名相同的BeginInvok和EndInvoke方法。

异步委托调用BeginInvok和EndInvoke方法,但在.NET Compact Framework中并不支持。

BeginInvoke方法触发你的异步方法,它和你想要执行的异步方法有相同的参数。另外还有两个可选参数,第一个是AsyncCallback委托是异步完成的回调方法。第二个是用户自定义对象,该对象将传递到回调方法中。BeginInvoke立即返回并且不等待完成异步的调用(继续执行该下面的代码,不需要等待)。BeginInvoke返回IAsyncResult接口,可用于检测异步调用的过程。

通过EndInvoke方法检测异步调用的结果。如果异步调用尚未完成,EndInvoke将阻塞调用线程,直到它完成。EndInvoke参数包括out和ref参数。

下面代码演示使用BeginInvoke和EndInvoke进行异步调用的四种常见方式。在调用BeginInvoke可以做以下工作:

  1. 做一些其他操作,然后调用EndInvoke方法阻塞线程直到该方法完成。
  2. 使用IAsyncResult.AsyncWaitHandle属性,使用它的WaitOne方法阻塞线程直到收到WaitHandle信号,然后调用EndInvoke。
  3. 检查BeginInvoke返回值IAsyncResult的状态来决定方法是否完成,然后调用EndInvoke方法。
  4. 通过在BeginInvoke方法中传递该委托,在回调方法中调用该委托的EenInvoke方法。

注意

无论你怎么使用,都必须调用EndInvoke方法结束你的异步调用。

下面通过模拟一个耗时的操作,实现上面说的那四种情况。

情况一:通过EndInovke阻塞线程,直到异步调用结束。

using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// <summary>/// 委托必须和要调用的异步方法有相同的签名/// </summary>/// <param name="callDuration">sleep时间</param>/// <param name="threadId">当前线程id</param>/// <returns></returns>public delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// <summary>/// 主函数/// </summary>/// <param name="args"></param>static void Main(string[] args){AsyncMethodCaller caller = new AsyncMethodCaller(TestMethodAsync);int threadid = 0;//开启异步操作IAsyncResult result = caller.BeginInvoke(3000, out threadid, null, null);for (int i = 0; i < 10; i++){Console.WriteLine("其它业务" + i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine("等待异步方法TestMethodAsync执行完成");string res = caller.EndInvoke(out threadid, result);Console.WriteLine("Completed!");Console.WriteLine(res);Console.Read();}/// <summary>/// 与委托对应的方法/// </summary>/// <param name="callDuration"></param>/// <param name="threadId"></param>/// <returns></returns>static string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw = new Stopwatch();sw.Start();Console.WriteLine("异步TestMethodAsync开始");for (int i = 0; i < 5; i++){   // 模拟耗时操作
                Thread.Sleep(callDuration);Console.WriteLine("TestMethodAsync:" + i.ToString());}sw.Stop();threadId = Thread.CurrentThread.ManagedThreadId;return string.Format("耗时{0}ms.", sw.ElapsedMilliseconds.ToString());}}
}

View Code

结果

由上图,可以看出,在BeginInvoke开启异步执行方法,会先执行其他的业务。通过EndInvoke方法,阻塞直到异步执行完毕,才会执行EndInvoke之后的代码。

情况二:通过WaitHandle属性阻塞线程。

你可以获得BeginInvoke的返回值的WaitHandle,并使用它的AsyncWaitHanlde属性。WaitHandle信号异步完成时,你可以通过调用WaitOne方法等待。

如果你使用WaitHandle,你可以在之前或者异步调用完成后进行其他的操作。但之后必须使用EndInvoke检查结果。

注意

当你调用EndInvoke方法时,等待句柄并不会自动关闭。如果你释放等待处理的所有引用,当垃圾回收等待句柄是,系统资源将被释放。一旦你完成使用等待句柄,通过WaitHandle的close方法,一次性显示关闭,这时的垃圾回收效率更高。

using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// <summary>/// 委托必须和要调用的异步方法有相同的签名/// </summary>/// <param name="callDuration">sleep时间</param>/// <param name="threadId">当前线程id</param>/// <returns></returns>public delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// <summary>/// 主函数/// </summary>/// <param name="args"></param>static void Main(string[] args){AsyncMethodCaller caller = new AsyncMethodCaller(TestMethodAsync);int threadid = 0;//开启异步操作IAsyncResult result = caller.BeginInvoke(3000, out threadid, null, null);for (int i = 0; i < 10; i++){Console.WriteLine("其它业务" + i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine("等待异步方法TestMethodAsync执行完成");//等待异步执行完毕信号
            result.AsyncWaitHandle.WaitOne();Console.WriteLine("收到WaitHandle信号");//通过EndInvoke检查结果string res = caller.EndInvoke(out threadid, result);//显示关闭句柄
            result.AsyncWaitHandle.Close();Console.WriteLine("关闭了WaitHandle句柄");Console.WriteLine("Completed!");Console.WriteLine(res);Console.Read();}/// <summary>/// 与委托对应的方法/// </summary>/// <param name="callDuration"></param>/// <param name="threadId"></param>/// <returns></returns>static string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw = new Stopwatch();sw.Start();Console.WriteLine("异步TestMethodAsync开始");for (int i = 0; i < 5; i++){   // 模拟耗时操作
                Thread.Sleep(callDuration);Console.WriteLine("TestMethodAsync:" + i.ToString());}sw.Stop();threadId = Thread.CurrentThread.ManagedThreadId;return string.Format("耗时{0}ms.", sw.ElapsedMilliseconds.ToString());}}
}

输出

情况三:检查BeginInvoke返回结果的状态。

可以通过BeginInvoke的返回结果的IsCompleted属性检查异步是否完成。你可以在异步没有完成的时候做其他的操作。

using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// <summary>/// 委托必须和要调用的异步方法有相同的签名/// </summary>/// <param name="callDuration">sleep时间</param>/// <param name="threadId">当前线程id</param>/// <returns></returns>public delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// <summary>/// 主函数/// </summary>/// <param name="args"></param>static void Main(string[] args){AsyncMethodCaller caller = new AsyncMethodCaller(TestMethodAsync);int threadid = 0;//开启异步操作IAsyncResult result = caller.BeginInvoke(1000, out threadid, null, null);for (int i = 0; i < 10; i++){Console.WriteLine("其它业务" + i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine("等待异步方法TestMethodAsync执行完成");//等待异步执行完毕信号//result.AsyncWaitHandle.WaitOne();//Console.WriteLine("收到WaitHandle信号");//通过循环不停的检查异步运行状态while (result.IsCompleted==false){Thread.Sleep(100);Console.WriteLine("异步方法,running........");}//异步结束,拿到运行结果string res = caller.EndInvoke(out threadid, result);//显示关闭句柄
            result.AsyncWaitHandle.Close();Console.WriteLine("关闭了WaitHandle句柄");Console.WriteLine("Completed!");Console.WriteLine(res);Console.Read();}/// <summary>/// 与委托对应的方法/// </summary>/// <param name="callDuration"></param>/// <param name="threadId"></param>/// <returns></returns>static string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw = new Stopwatch();sw.Start();Console.WriteLine("异步TestMethodAsync开始");for (int i = 0; i < 5; i++){   // 模拟耗时操作
                Thread.Sleep(callDuration);Console.WriteLine("TestMethodAsync:" + i.ToString());}sw.Stop();threadId = Thread.CurrentThread.ManagedThreadId;return string.Format("耗时{0}ms.", sw.ElapsedMilliseconds.ToString());}}
}

View Code

输出

其它业务0
其它业务1
其它业务2
其它业务3
其它业务4
其它业务5
其它业务6
其它业务7
其它业务8
其它业务9
等待异步方法TestMethodAsync执行完成
异步TestMethodAsync开始
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
TestMethodAsync:0
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
TestMethodAsync:1
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
TestMethodAsync:2
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
TestMethodAsync:3
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
异步方法,running........
TestMethodAsync:4
异步方法,running........
关闭了WaitHandle句柄
Completed!
耗时5031ms.

情况四:通过在回调方法中。

如果需要在异步完成后需要做一些其他的操作,你可以在异步完成时执行一个回调方法。在该回调方法中做处理。

首先需要定义一个回调方法。

using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// <summary>/// 委托必须和要调用的异步方法有相同的签名/// </summary>/// <param name="callDuration">sleep时间</param>/// <param name="threadId">当前线程id</param>/// <returns></returns>public delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// <summary>/// 主函数/// </summary>/// <param name="args"></param>static void Main(string[] args){AsyncMethodCaller caller = new AsyncMethodCaller(TestMethodAsync);int threadid = 0;//开启异步操作IAsyncResult result = caller.BeginInvoke(1000, out threadid, callBackMethod, caller);for (int i = 0; i < 10; i++){Console.WriteLine("其它业务" + i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine("等待异步方法TestMethodAsync执行完成");//等待异步执行完毕信号//result.AsyncWaitHandle.WaitOne();//Console.WriteLine("收到WaitHandle信号");//通过循环不停的检查异步运行状态//while (result.IsCompleted==false)//{//    Thread.Sleep(100);//    Console.WriteLine("异步方法,running........");//}//异步结束,拿到运行结果//string res = caller.EndInvoke(out threadid, result);////显示关闭句柄//result.AsyncWaitHandle.Close();Console.WriteLine("关闭了WaitHandle句柄");//Console.WriteLine(res);
            Console.Read();}/// <summary>/// 异步方法回调方法,异步执行完毕,会回调该方法/// </summary>/// <param name="ar"></param>private static void callBackMethod(IAsyncResult ar){AsyncMethodCaller caller = ar.AsyncState as AsyncMethodCaller; string result = caller.EndInvoke(out int threadid, ar);Console.WriteLine("Completed!");Console.WriteLine(result);}/// <summary>/// 与委托对应的方法/// </summary>/// <param name="callDuration"></param>/// <param name="threadId"></param>/// <returns></returns>static string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw = new Stopwatch();sw.Start();Console.WriteLine("异步TestMethodAsync开始");for (int i = 0; i < 5; i++){   // 模拟耗时操作
                Thread.Sleep(callDuration);Console.WriteLine("TestMethodAsync:" + i.ToString());}sw.Stop();threadId = Thread.CurrentThread.ManagedThreadId;return string.Format("耗时{0}ms.", sw.ElapsedMilliseconds.ToString());}}
}

总结

在项目中遇到的有参数又返回值的情况,如何在回调方法中拿到委托和传递的参数,当时卡这里了,后来查看情况四的情况,才得以解决。这里也再学习一下。

转载于:https://www.cnblogs.com/wolf-sun/p/5675791.html

[C#基础]c#中的BeginInvoke和EndEndInvoke相关推荐

  1. c#中的BeginInvoke和EndEndInvoke 摘要

    摘要 异步这东西,真正用起来的时候,发现事情还是挺多的,最近在项目中用到了异步的知识,发现对它还是不了解,处理起来,走了不少弯路.觉得还是补一补还是很有必要的. MSDN原文地址:https://ms ...

  2. 计算机应用公共课程,公共基础课程中计算机应用管理制度

    公共基础课程中计算机应用管理制度 作者:职称驿站 浏览量:14925 时间:2017-11-04 新科技技术的不断发展建设是带动教学发展.社会进步等等方面的因素.同时对于计算机应用上的建设发展来说也是 ...

  3. R语言使用R基础安装中的glm函数构建乳腺癌二分类预测逻辑回归模型、分类预测器(分类变量)被自动替换为一组虚拟编码变量、summary函数查看检查模型、使用table函数计算混淆矩阵评估分类模型性能

    R语言使用R基础安装中的glm函数构建乳腺癌二分类预测逻辑回归模型(Logistic regression).分类预测器(分类变量)被自动替换为一组虚拟编码变量.summary函数查看检查模型.使用t ...

  4. Java基础-Java中的堆内存和离堆内存机制

    Java基础-Java中的堆内存和离堆内存机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 转载于:https://www.cnblogs.com/yinzhengjie/p/9 ...

  5. Java基础-JAVA中常见的数据结构介绍

    Java基础-JAVA中常见的数据结构介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是数据结构 答:数据结构是指数据存储的组织方式.大致上分为线性表.栈(Stack) ...

  6. 计算机应用基础教学实践活动,计算机应用基础与中职数学课程融合教学实践.doc...

    计算机应用基础与中职数学课程融合教学实践.doc PAGE \* MERGEFORMAT 7 计算机应用基础与中职数学课程融合教学实践--以数据的图示单元教学为例吴晓进[摘 要] 中职<数学&g ...

  7. 计算是计算机科学独有的方法,大学计算机基础教学中的计算思维培养.doc

    大学计算机基础教学中的计算思维培养 龚沛曾 杨志强 ? 2012-06-26 08:58:58 来源:<中国大学教学>2012年第05期 摘要:首先仔细地分析了计算思维的定义,提出了计算思 ...

  8. 计算机基础中怎么评价,浅谈职校计算机基础教学中的教学评价

    浅谈职校计算机基础教学中的教学评价 在我们具体实施任务驱动法的教学过程中,教学评价是非常重要的环节.教学评价是计算机课 (本文共2页) 阅读全文>> 随着时代的发展,人们对高等教育发展的关 ...

  9. 基础实验中的抗体选择过程和避坑Tips

    基础实验中,抗原抗体结合反应是我们很常运用的一个原理,像免疫组化.免疫荧光.免疫印迹试验(Western Blot).ELISA等都是常见又很重要的几种实验.而实验的关键步骤,就在于抗体的选择.抗体选 ...

最新文章

  1. 【廖雪峰python入门笔记】set
  2. 0基础学python难吗-0基础学Python有多难?该怎么入门?
  3. linux php gd库安装,Linux系统gd库安装步骤说明
  4. 11.考虑用排序的vector替代关联容器
  5. 机器学习 数据增加_【机器学习】数据降维概述
  6. 网络切片技术缺点_一文读懂网络切片 - 技术综合版块 - 通信人家园 - Powered by C114...
  7. android gif转jpg格式文件,android使用多张图片合成gif文件
  8. Win10开机一直转圈圈怎么办?一直转圈进不去系统的解决方法
  9. pyqt 取鼠标处文字_顶级玩家首选 赛睿QcK Edge鼠标垫体验评测
  10. EJB的beans们
  11. 10. Django基础:静态文件
  12. 微擎系统 微信支付 get_brand_wcpay_request:fail
  13. 来自大数据的反思:需要你读懂的10个小故事
  14. 软考高项论文怎么写?——软考高项笔记9
  15. C++:建立一个被称为sroot()的函数,返回其参数的二次方根。重载sroot()3次,让它返回整数、长整数与双精度的二次方根
  16. 2020 年博客总结
  17. 什么是命令提示符、打开命令提示符、命令提示符打开浏览器某网站等操作
  18. pcf8591c语言编程,ADDA系列PCF8591的驱动程序
  19. 正大国际期货:为什么外盘期货顺势交易这么难
  20. 设计模式读书笔记汇总

热门文章

  1. hdu 1280用hash解决。。
  2. Swift:如何判断一个对象是否是某个类(或其子类)的实例
  3. SAP HANA企业级培训系列课程第一部分
  4. [转] 最近点对距离问题
  5. poj 2531(dfs)
  6. IOS OC项目的单例模式
  7. java的几_Java的几种时间
  8. python选取元音开头的单词_一学生易错词汇aan的选择元音字母开头的单词用an辅音字母...
  9. docker容器mysql头文件_在Docker容器中使用MySQL数据库
  10. XSS跨站脚本(web应用)——XSS跨站脚本防御(三)