关于C#委托三种调用的分享
关于C#委托三种调用的分享
一、同步调用
1、同步调用会按照代码顺序来执行
2、同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了。
举个栗子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
namespace Test
{
public delegate int AddHandler(int a, int b); public class Calc { public static int Add(int a, int b) { Console.WriteLine("开始计算:" + a + "+" + b); Thread.Sleep(3000); //模拟该方法运行三秒 Console.WriteLine("计算完成!"); return a + b; } } class Program { static void Main(string[] args) { Console.WriteLine("===== 同步调用 SyncInvokeTest ====="); AddHandler handler = new AddHandler(Calc.Add); int result = handler.Invoke(1, 2); Console.WriteLine("继续做别的事情。。。"); Console.WriteLine(result); Console.ReadKey(); } }
}
- 问:为什么Invoke的参数和返回值和AddHandler委托是一样的呢?
- 答:Invoke方法的参数很简单,一个委托,一个参数表(可选),
而Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。
Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,
如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,
然后执行委托指向的方法。不管当前线程是不是UI线程,
Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的
线程(如果需要的话),返回。
所以Invoke方法的参数和返回值和调用他的委托应该是一致的。
二、异步调用
1、异步调用不阻塞线程,而是把调用塞到线程池中,
2、程序主线程或UI线程可以继续执行。
3、委托的异步调用通过BeginInvoke和EndInvoke来实现。
举个栗子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
namespace Test
{
public delegate int AddHandler(int a, int b); public class Calc { public static int Add(int a, int b) { Console.WriteLine("开始计算:" + a + "+" + b); Thread.Sleep(3000); //模拟该方法运行三秒 Console.WriteLine("计算完成!"); return a + b; } } class Program { static void Main(string[] args) { Console.WriteLine("===== 异步调用 AsyncInvokeTest ====="); AddHandler handler1 = new AddHandler(Calc.Add); //IAsyncResult: 异步操作接口(interface) //BeginInvoke: 委托(delegate)的一个异步方法的开始 IAsyncResult result1 = handler1.BeginInvoke(1, 2, null, null); Console.WriteLine("继续做别的事情1。。。"); //异步操作返回 Console.WriteLine(handler1.EndInvoke(result1));//会等待加法类计算,如果没计算好就堵塞线程 Console.WriteLine("继续做别的事情2。。。"); Console.ReadKey(); } }
}
注意:
- BeginInvoke : 开始一个异步的请求,调用线程池中一个线程来执行,
- 返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,
- 它存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
- 注意: BeginInvoke和EndInvoke必须成对调用.即使不需要返回值,
- 但EndInvoke还是必须调用,否则可能会造成内存泄漏。
结果:
可以看到,主线程并没有等待,而是直接向下运行了。
但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。
三、异步回调
用回调函数,当调用结束时会自动调用回调函数,解决了为等待调用结果,而让线程依旧被阻塞的局面。
举个栗子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
namespace Test
{
public delegate int AddHandler(int a, int b); public class Calc { public static int Add(int a, int b) { Console.WriteLine("开始计算:" + a + "+" + b); Thread.Sleep(3000); //模拟该方法运行三秒 Console.WriteLine("计算完成!"); return a + b; } } class Program { static void Main(string[] args) { Console.WriteLine("===== 异步回调 AsyncInvokeTest ====="); AddHandler handler2 = new AddHandler(Calc.Add); //异步操作接口(注意BeginInvoke方法的不同!) IAsyncResult result2 = handler2.BeginInvoke(1, 2, new AsyncCallback(MyCallBack), "AsycState:OK"); Console.WriteLine("继续做别的事情。。。"); Console.ReadKey(); } static void MyCallBack(IAsyncResult result) { //result 是“加法类.Add()方法”的返回值 //AsyncResult 是IAsyncResult接口的一个实现类,空间:System.Runtime.Remoting.Messaging //AsyncDelegate 属性可以强制转换为用户定义的委托的实际类。 AddHandler handler = (AddHandler)((AsyncResult)result).AsyncDelegate; Console.WriteLine(handler.EndInvoke(result)); Console.WriteLine(result.AsyncState); } }
}
委托的类型为AddHandler,则为了访问 AddHandler.EndInvoke,
result 是“加法calc.Add()方法”的返回值
AsyncResult 是IAsyncResult接口的一个实现类,空间:System.Runtime.Remoting.Messaging
必须将异步委托强制转换为 AddHandler。可以在异步回调函数(类型为 AsyncCallback)中调用 AddHandler.EndInvoke,以获取最初提交的 AddHandler.BeginInvoke 的结果。
ok,三种委托调用的分享就到这里了,有疑问的欢迎指正!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
为什么我觉得 Java 的 IO 很复杂?
为什么我觉得 Java 的 IO 很复杂? 初学者觉得复杂是很正常的,归根结底是因为没有理解JavaIO框架的设计思想: 可以沿着这条路想一想: 1,学IO流之前,我们写的程序,都是在内存里自己跟自己玩。比如,你声明个变量,创建个数组,创建个集合,写一个排序算法,模拟一个链表,使用一些常用API,现在回想一下,是不是在只是自己在内存里玩一玩?计算机组成包括运算器,控制器,存储器,输入设备,输出设备。那么你前面的工作,仅仅够你的程序和内存以及CPU打打交道,如果你需要操作外部设备呢?比如键盘,显示器,再比如,最常见的外设:硬盘?甚至未来世界里的每家每户都有的机器人,“如何让你的程序和机器人进行交互呢?” 2,所以程序设计语言必须要提供程序与外部设备交互的方式,这就是IO框架的由来。我们需要和外部设备进行数据的交互。那么,计算机是通过什么和外部进行交互的呢?很简单就能想到:数据线。数据线里传播的是什么呢?一个词:比特流。比特就是bit的谐音,计算机中“位”的意思,代表0或1。1位或者1bit,就是一个0或一个1。但是,毕竟0或1不能表示什么,所以计算机更常见的基本单位是字节,也就是用8位0...
- 下一篇
震惊!当Python遇到Excel后,将开启你的认知虫洞
震惊!当Python遇到Excel后,将开启你的认知虫洞 本文主要内容: Excel,你为什么如此强大 软件开发也需要团队作战 Excel的集成方案演化 macOS特有的集成方案:applescript Python与Excel集成,有哪些好处 了解多个技术领域,可以间接提高自己的IQ 提高开发效率的利器:生态渗透 上代码:Python到底如何与Excel交互 用Python替代VBA 本文主要讲Python与Excel的关系以及集成方案,Office家族的其他成员,如Word、PowerPoint与Excel拥有类似的功能,Python同样可以与Word、PowerPoint等Office成员结合,这些内容我以后会写文章讲解。 我相信看这篇文章的大多数人都是程序员。在广大程序员的眼里,Excel以及Office家族的其他成员完全不能与Python、Java、Sprint Boot这些技术相比。Office被贴上的标签就是:非专业人员的工具。是由那些体制内的人、会计、业务人员使用的工具,其实这是对Excel的最大误解。1. Excel,你为什么如此强大 Excel从一问世开始,定位就是...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装