C#当中的BeginInvoke和EndInvoke
我们已经知道 C#当中 存在async/await 、BackGroudWorker类以及TPL(任务并行库)。当然C#还有一些旧的模式来支持异步编程。参考《C#图解教程》
1. BeginInovke和EndInvoke简单介绍
delegate long MyDel(int first, int second); class Program
{
static long Sum(int x, int y)
{
Console.WriteLine("------Inside Sum@{0}", DateTime.Now.ToString());
Thread.Sleep();
return x + y;
} static void Main(string[] args)
{
MyDel del = new MyDel(Sum); Console.WriteLine("Before BeginInvoke---@{0}", DateTime.Now.ToString());
IAsyncResult iar = del.BeginInvoke(, , null, null);
Console.WriteLine("After BeginInvoke@{0}", DateTime.Now.ToString()); Console.WriteLine("Doing stuff@{0}", DateTime.Now.ToString()); long result = del.EndInvoke(iar);
Console.WriteLine("End Invoke@{0}", DateTime.Now.ToString()); Console.WriteLine("After EndInvoke: {0}", result); Console.ReadKey(); }
}
如上代码,定义了一个委托 MyDel ,并且在调用的时候把Sum方法传给了它的对象。一般情况下我们调用这个委托对象,它就会调用他调用列表中包含的方法。就想调用方法一样,这是同步完成的。
但是如果委托对象在调用列表中只有一个方法(引用方法),它就可以异步的去执行这个方法。BeginInovke和EndInvoke就是用来做这个事的。我们可以用如下的方式使用:
①当我们调用BeginInvoke方法的时候,他开始在一个独立的线程上执行引用方法,并且立即返回到原始线程。原始线程可以继续,而引用方法会在想吃的线程中并行执行。
②当程序希望获取已完成的异步方法的结果时,可以检查BeginInvoke返回的IAsyncResult的IsCompleted属性,或者调用委托的EndInvoke方法来等待委托执行完成。
上面的使用过程就引出的三种模式:
①等待-直到完成 原始线程在发起了异步方法以及做了一些其他处理之后,原始线程就中断并且等待异步方法执行完成之后再继续。
②轮询 ,原始线程定期检查发起的线程是否完成,如果没有则可以继续做其他的事情,
③回调 原始线程一直执行,无需等待或者检查发起的线程是否完成,发起的线程中的引用发放完成之后,发起的线程会调用回调方法,由回调方法在调用的EndInvoke之前处理异步方法的结果。
2.BeginInovke和EndInvoke详细
对于 BeginInvoke 方法,有几个注意的地方
① 我们可以根据上面的代码知道,BeginInvoke的参数包含如下两个部分
l 引用方法的参数
l CallBack参数和State参数
②BeginInvoke 会在线程池中找到一个线程,让引用方法运行在该线程上
③BeginInvoke 返回给调用线程一个实现IAsyncResult接口的对象的引用。这个接口引用包含了在线程池线程中运行的异步方法的状态。可以判断这个状态来确定异步方法是否结束。
// 3和5是引用方法参数,两个null分别是Callback参数和State参数
// iar是新线程的信息
IAsyncResult iar = del.BeginInvoke(3, 5, null, null);
对于 EndInvoke 方法,有几个注意的地方
①他的参数是上面BegionInvoke返回的IAsyncResult接口的引用对象,传入这个对象是便于EndInvoke去找到引用方法运行的线程。并且这个参数置于参数列表最后一个。EndInvoke提供了从异步方法调用的所有输出,包括ref和out参数。如果委托的引用方法有ref和out参数,他们必须包含在EndInvoke的参数列表当中
IAsyncResult iar2 = del2.BeginInvoke(3, 5, out res, null, null);
del2.EndInvoke(out res, iar2);
②如果线程已经退出了,EndInvoke会做如下事情:
清理退出的线程的状态并且释放资源
找到引用方法的返回值,并作为自己的返回值
③如果EndInovke发现线程还在运行中,那么调用线程就会停止并等待,直到清理完毕并返回值。
④因为EndInvoke会去清理线程信息,所以BeginInvoke和EndInvoke必须成对使用。
⑤如果异步方法出现异常,那么在调用EndInvoke的时候会抛出异常。
3.AsyncResult类
上面说BeginInvoke方法返回了一个IAsyncResult接口的引用对象(内部是AsyncResult类的对象),AsyncResult类型表现了异步方法的状态。下面是这类的主要组成部分:
4.三种模式
① 等待-直到完成 (比较简单的模式)
//开始执行异步方法
IAsyncResult iar = del.BeginInvoke(3, 5, null, null);
//Do Something 耗时
del2.EndInvoke(iar);
像上面的代码,BeginInvoke之后,做了一些事情,然后调用EndInvoke来处理结果,这种方式就是等待-直到完成的模式。
②轮询模式
轮询模式中,原始的线程发起了异步的方法调用,做一些事情,然后使用IAsyncResult中的IsComplete熟悉来定期检查开启的线程是否完成。如果未完成就在去做一些其他事情。
delegate long MyDel(int first, int second); class Program
{
static long Sum(int x, int y)
{
Console.WriteLine("--Inside Sum@{0}", DateTime.Now.ToString());
Thread.Sleep();
return x + y;
} static void Main(string[] args)
{
MyDel del = new MyDel(Sum);
//开始执行异步方法
IAsyncResult iar = del.BeginInvoke(, , null, null);
//轮询开始
while (!iar.IsCompleted)
{
//未完成,执行下面的语句
for (long i = ; i < ; i++)
;
}
//执行完成调用EndInvoke获取结果
long result = del.EndInvoke(iar);
Console.ReadKey();
}
③回调模式
前两种都是主动方式的,原始线程一直在监控这新开启的线程。但是回调是被动的,一旦原始线程发起了异步方法,它就自己管自己了,不在考虑同步。
当异步方法调用结束之后,系统调用一个用户自定义的方法来处理结果,并且调用委托的EndInvoke方法。这个用户自定义的方法就是回调方法。
上面的BegionInvoke中写过,他会有两个参数一个Callback参数和一个State参数.
CallBack参数:是回调方法的名称。
State参数:可以是null,或者传入回调方法的一个对象的引用。我们可以用IAsyncResult参数的AsyncState属性来获取这个对象,参数的类型是object。
a.回调方法:
回调方法的签名和返回类型必须和 AsyncCallback委托类型所描述的形式一致。
两种方式,构建这个AsyncCallback参数
new AsyncCallback 对象
IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone),null);
直接传回调方法的名称
IAsyncResult iar = del.BeginInvoke(3, 5, CallWhenDone, null);
其中 CallWhenDone 如下:
static void CallWhenDone(IAsyncResult iar)
{
AsyncResult ar = (AsyncResult)iar;
MyDel del = (MyDel)ar.AsyncDelegate;
//回调方法中调用了EndInvoke
long result = del.EndInvoke(iar);
}
b.在回调方法中调用EndInvoke
上面代码中,在回调中使用了EndInvoke,上文中说到 EndInvoke的调用,是委托的调用,并且需要传入一个IAsyncResult的接口对象的引用。
所以想要在回调方法里面,调用这个EndInvoke,就得拿到两个东西一个是委托对象、一个是IAsyncResult,由于我们AsyncCallback委托本身就是必须要传入IAsyncResult 的,所以这个比较容易,剩下的就是委托对象本身了。在AsyncResult类小节里面我看到,它里面存着一个 AsyncDelegate(它就是委托对象的引用),还有就是 IAsyncResult接口对象在内部就是AsyncResult类对象。所以才可以像上main的代码,通过强制类型转换得到MyDel的对象。
第二种方法就是如果State参数没有用处,可以通过State参数,把委托的对象传过去。
调用的地方,最后一个参数传入del
IAsyncResult iar = del.BeginInvoke(3, 5, new AsyncCallback(CallWhenDone),del);
回调方法:
static void CallWhenDone(IAsyncResult iar)
{
MyDel del = (MyDel)iar.AsyncState;
long result = del.EndInvoke(iar);
}
C#当中的BeginInvoke和EndInvoke的更多相关文章
- BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题
BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题 原文:http://www.sufeinet.com/thread-3707-1-1.html 大家可以先看看我上 ...
- C#线程系列讲座(1):BeginInvoke和EndInvoke方法
一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行.这就需要在同一个进程中开启多个 ...
- [转]BeginInvoke和EndInvoke方法浅析
开发语言:C#3.0 IDE:Visual Studio 2008 一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提 ...
- delegate 中的BeginInvoke和EndInvoke方法
开发语言:C#3.0 IDE:Visual Studio 2008 一.C#线程概述 在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能 ...
- C#线程应用实例(part1) 之 BeginInvoke和EndInvoke
最近这个公司是做 winfrom 开发的 , 这段时间就好好的学学WCF , 公司框架什么的自己去琢磨! 这里主要写一些 winfrom 中 用到的一些陌生 技术 1.BeginInvoke 以前B ...
- 委托的BeginInvoke和EndInvoke方法
.NET Framework 允许异步调用任何方法,为了实现异步调用目标,需要定义与被调用方法具有相同签名的委托.公共语言运行时会自动使用适当的签名为该委托定义 BeginInvoke 和 EndIn ...
- (二)异步方法BeginInvoke和EndInvoke
.Net framework可以让你异步调用任何方法,你可以定义一个与你要调用的方法的签名相同的委托.公共语言运行时将自动为该委托定义与签名相同的BeginInvok和EndInvoke方法. Beg ...
- 用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程
让我们首先了解下什么时候用到C#异步调用: .NET Framework 允许您C#异步调用任何方法.定义与您需要调用的方法具有相同签名的委托:公共语言运行库将自动为该委托定义具有适当签名的Begin ...
- 异步使用委托delegate --- BeginInvoke和EndInvoke方法
当我们定义一个委托的时候,一般语言运行时会自动帮委托定义BeginInvoke 和 EndInvoke两个方法,这两个方法的作用是可以异步调用委托. 方法BeginInvoke有两个参数: Async ...
随机推荐
- 【ARTS】01_39_左耳听风-201900805~20190811
ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...
- oracle jdk和openjdk区别;idea如何加载jdk源码并调试jdk代码
两个jdk的区别 oracle jdk是sun/oracle(甲骨文)公司的,部分jdk开源:相对比较稳定,使用的比较多. openjdk是完全开源的,据说是官方oracle唯一承认的开源版本. id ...
- ubuntu 12.04 下LVS的一些搭建心得和资料整理
最近项目上需要使用到IPVS进行负载均衡,针对外部传来的HTTP请求,分摊到多台服务器上进行处理,所以看了一下这方面的资料,在这里纪录一下. Lvs是基于IP层和内容分发请求的负载均衡方法(所以也可以 ...
- 《Fluid Engine Development》 学习笔记4-预测校正不可压缩SPH-PCISPH
传统SPH方案的主要问题之一是时间步长限制.在原始的SPH中,我们首先从当前设置计算密度,使用EOS计算压强,应用压力梯度,然后运行时间积分.这个过程意味着只需要一定的压缩量就可以触发内核半径内的压力 ...
- Vue 开发技巧或者说Vue知识点梳理(转,自个学习)
Vue 组件通讯 ——常见使用场景可以分为三类: 父子通信: 父向子传递数据是通过 props,子向父是通过 events($emit):通过父链 / 子链也可以通信($parent / $child ...
- 日常工作问题解决:du命令详解
目录 1.导读 1.1 命令格式 1.2 命令功能 1.3 命令参数 2.实例 2.1 实例1:显示目录或者文件所占空间 2.2 实例2:显示指定文件所占空间 2.3 实例3:查看指定目录所占空间 2 ...
- JAVA MAC 比较大小
2个MAC String mac_1="AAAAAAAAAAAA"; String mac_1="AAAAAAAAAAAB"; 方法一: int a = 0; ...
- 服务提供者框架讲解 之 myJDBC
利用一个简单的myJDBC,讲一下'服务提供者框架'的思想.主要是思想 目录 什么是 服务提供者框架 代码讲解 服务接口 服务提供者接口 服务注册API.服务访问API 静态工厂方法 服务实现类 – ...
- Win10 彻底关闭 Windows Defender
1.使用快捷键 WIN+R 调出运行工具,然后再输入组策略命令 gpedit.msc 再点击确定. 2.进入组策略在计算机配置下面的管理模板,Windows 组件就可以看到 Windows Defen ...
- python — 索引与pymysql模块
1. 索引 1.1 索引原理 1.什么是索引 ?-- 目录 索引就是建立起的一个在存储表阶段就有的一个存储结构,能在查询的时候加速. 2.索引的重要性: 读写比例 为 10:1,所有读(查询)的速度就 ...