C#委托的异步调用[转]

本文将主要通过“同步调用”、“异步调用”、“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊。

首先,通过代码定义一个委托和下面三个示例将要调用的方法:

/*添加的命名空间
using System.Threading;
using System.Runtime.Remoting.Messaging;
*/
    public delegate int AddHandler(int a,int b);
    
public class 加法类
    {
        
public static int Add(int a, int b)
        {
            Console.WriteLine("开始计算:" + a + "+" + b);
            Thread.Sleep(3000); //模拟该方法运行三秒
            Console.WriteLine("计算完成!");
            
return a + b;
        }
    }

同步调用

委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。

public class 同步调用
{
        
static void Main()
        {
            Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);
            
int result = handler.Invoke(12);

            Console.WriteLine("继续做别的事情。。。");

            Console.WriteLine(result);
            Console.ReadKey();
        }
        
/*运行结果:
         ===== 同步调用 SyncInvokeTest =====
         开始计算:1+2
         计算完成!
         继续做别的事情。。。
         3       */
}

同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了。

异步调用

异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。
委托的异步调用通过BeginInvoke和EndInvoke来实现。

public class 异步调用
{
        
static void Main()
        {
            Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);

            
//IAsyncResult: 异步操作接口(interface)
            
//BeginInvoke: 委托(delegate)的一个异步方法的开始
            IAsyncResult result = handler.BeginInvoke(12nullnull);

            Console.WriteLine("继续做别的事情。。。");

            
//异步操作返回
            Console.WriteLine(handler.EndInvoke(result));
            Console.ReadKey();
        }
        
/*运行结果:
         ===== 异步调用 AsyncInvokeTest =====
         继续做别的事情。。。
         开始计算:1+2
         计算完成!
         3       */
}

可以看到,主线程并没有等待,而是直接向下运行了。
但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。

 异步委托,也可以参考如下写法:

Action<object> action=(obj)=>method(obj);
action.BeginInvoke(obj,ar=>action.EndInvoke(ar),null);

简简单单两句话就可以完成一部操作。

异步回调

用回调函数,当调用结束时会自动调用回调函数,解决了为等待调用结果,而让线程依旧被阻塞的局面。

public class 异步回调
{
        
static void Main()
        {
            Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);

            
//异步操作接口(注意BeginInvoke方法的不同!)
            IAsyncResult result = handler.BeginInvoke(1,2,new AsyncCallback(回调函数),"AsycState:OK");
            
            Console.WriteLine("继续做别的事情。。。");
            Console.ReadKey();
        }

        
static void 回调函数(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);
        }
        
/*运行结果:
        ===== 异步回调 AsyncInvokeTest =====
        开始计算:1+2
        继续做别的事情。。。
        计算完成!
        3
        AsycState:OK
                 
*/
}

我定义的委托的类型为AddHandler,则为了访问 AddHandler.EndInvoke,必须将异步委托强制转换为 AddHandler。可以在异步回调函数(类型为 AsyncCallback)中调用 MAddHandler.EndInvoke,以获取最初提交的 AddHandler.BeginInvoke 的结果。 

问题:

(1)int result = handler.Invoke(1,2);
为什么Invoke的参数和返回值和AddHandler委托是一样的呢?
答:
Invoke方法的参数很简单,一个委托,一个参数表(可选),而Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,然后执行委托指向的方法。不管当前线程是不是UI线程,Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的线程(如果需要的话),返回。
所以Invoke方法的参数和返回值和调用他的委托应该是一致的。

(2)IAsyncResult result = handler.BeginInvoke(1,2,null,null);

BeginInvoke : 开始一个异步的请求,调用线程池中一个线程来执行,
返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,他存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
注意: BeginInvoke和EndInvoke必须成对调用.即使不需要返回值,但EndInvoke还是必须调用,否则可能会造成内存泄漏。

(3)IAsyncResult.AsyncState 属性:
获取用户定义的对象,它限定或包含关于异步操作的信息。 例如:

static void AddComplete(IAsyncResult result) 
{   
      AddHandler handler = (AddHandler)result.AsyncState;    
      Console.WriteLine(handler.EndInvoke(result)); 
      。。。。。
}

完整代码如下:

ContractedBlock.gifExpandedBlockStart.gif三个示例的全部代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace ConsoleTest
{
    
public delegate int AddHandler(int a,int b);
    
public class 加法类
    {
        
public static int Add(int a, int b)
        {
            Console.WriteLine("开始计算:" + a + "+" + b);
            Thread.Sleep(3000); //模拟该方法运行三秒
            Console.WriteLine("计算完成!");
            
return a + b;
        }
    }

    
public class 同步调用
    {
        
static void Main()
        {
            Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);
            
int result = handler.Invoke(12);

            Console.WriteLine("继续做别的事情。。。");

            Console.WriteLine(result);
            Console.ReadKey();
        }
        
/*运行结果:
         ===== 同步调用 SyncInvokeTest =====
         开始计算:1+2
         计算完成!
         继续做别的事情。。。
         3       */
    }

    
public class 异步调用
    {
        
static void Main()
        {
            Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);

            
//IAsyncResult: 异步操作接口(interface)
            
//BeginInvoke: 委托(delegate)的一个异步方法的开始
            IAsyncResult result = handler.BeginInvoke(12nullnull);

            Console.WriteLine("继续做别的事情。。。");

            
//异步操作返回
            Console.WriteLine(handler.EndInvoke(result));
            Console.ReadKey();
        }
        
/*运行结果:
         ===== 异步调用 AsyncInvokeTest =====
         继续做别的事情。。。
         开始计算:1+2
         计算完成!
         3       */
    }

    
public class 异步回调
    {
        
static void Main()
        {
            Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);

            
//异步操作接口(注意BeginInvoke方法的不同!)
            IAsyncResult result = handler.BeginInvoke(1,2,new AsyncCallback(回调函数),"AsycState:OK");
            
            Console.WriteLine("继续做别的事情。。。");
            Console.ReadKey();
        }

        
static void 回调函数(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);
        }
        
/*运行结果:
        ===== 异步回调 AsyncInvokeTest =====
        开始计算:1+2
        继续做别的事情。。。
        计算完成!
        3
        AsycState:OK
                 
*/
    }
}

来源:http://www.cnblogs.com/yinhu435/archive/2009/10/19/1585958.html

作者: XuGang   网名:钢钢
出处: http://xugang.cnblogs.com
声明: 本文版权归作者和博客园共有!转载时必须保留此段声明,且在文章页面明显位置给出原文连接。

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

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

相关文章

钉钉微应用怎么进入_蓝凌携手钉钉走进越秀地产,零距离热聊企业数字化转型...

8月18日&#xff0c;蓝凌携手钉钉一同走进越秀地产&#xff0c;举办了《地产行业数字化实战闭门分享会》主题活动&#xff0c;与30余名嘉宾欢聚一堂&#xff0c;体验智慧管理实践与数字工作模式&#xff0c;探索企业数字化转型升级之道。越秀地产CIO陈磊、越秀地产信息总监郑毅…

mysql5.7半自动同步设置【转】

mysql的主从复制主要有3种模式&#xff1a; a..主从同步复制&#xff1a;数据完整性好&#xff0c;但是性能消耗高 b.主从异步复制&#xff1a;性能消耗低&#xff0c;但是容易出现主从数据唯一性问题 c.主从半自动复制&#xff1a;介于上面两种之间。既能很好的保持完整性&…

Android之旅---广播(BroadCast)

什么是广播在Android中&#xff0c;Broadcast是一种广泛运用的在应用程序之间传输信息的机制。我们拿广播电台来做个比方。我们平常使用收音机收音是这样的&#xff1a;许许多多不同的广播电台通过特定的频率来发送他们的内容&#xff0c;而我们用户只需要将频率调成和广播电台…

python牛客网编程题_【面经】小米软件开发一面(python)面经 2020 2020

作者&#xff1a;JessyTsuihttps://www.nowcoder.com/discuss/580721?type2&order0&pos15&page1&channel-1&source_iddiscuss_tag_nctrack来源&#xff1a;牛客网小米软件开发一面(python)面经一共三轮技术面&#xff0c;第四轮是HR面&#xff0c;已OC&am…

c# 数组和集合

数组是最为常见的一种结构&#xff0c;是相同类型的、用一个标识符封装到一起的j基本类型数据序列或对象序列&#xff0c;可以用一个统一的数组名和下标来唯一确定数组中的元素。实质上数组是一个简单的线性序列&#xff0c;因此数组访问起来很快。而集合可以看成一种特殊的数组…

和vs版本关系_栈局部变量优化探究,意外发现了 vs 的一个 bug ?

缘起 我在《栈又溢出了》一文中记录了一个奇怪的栈溢出问题。虽然解决了&#xff0c;但是总感觉哪里不太合理。我想&#xff0c;vs 一定有一个合理的设置。一起折腾起来吧&#xff01;查找工程设置 本以为能找到某个编译选项对局部变量占用内存的行为进行控制。看遍了工程设置也…

在ubuntu 16.04上安装tensorflow,并测试成功

用下面代码测试安装&#xff1a; 1 #! /usr/bin/python2 # -*- coding: utf-8 -*-3 4 import tensorflow as tf5 import numpy6 import matplotlib.pyplot as plt7 rng numpy.random8 9 learning_rate 0.01 10 training_epochs 1000 11 display_step 50 12 #数据集x 13 tra…

redis客户端连接数量_实战解析无所不知的Redis拓展应用——Info,进阶学习,无所不能...

前言学习是一个持续的过程。像咱们一直在更新的Redis学习内容&#xff0c;由基础结构&#xff0c;到原理应用&#xff0c;再到集群搭建&#xff0c;了解的够充分了&#xff0c;咱们接着又介绍Redis拓展应用&#xff0c;将知识面拓宽&#xff0c;毕竟技术都是相通的&#xff0c;…

【Excle数据透视】如何用含有单元格的数据来创建数据透视

取消合并单元格&#xff0c;填充相同内容项&#xff0c;然后创建数据透视表. 如下图&#xff1a;需要使用数据创建数据透视表 步骤一 开始→格式刷&#xff0c;然后对单元格区域G2&#xff1a;G15使用格式刷功能&#xff0c;保留合并单元格格式 步骤二 选中A2&#xff1a;A18区…

css 超出文字头尾相接滚动_前端的一些雕虫小技,从100%和滚动条说起

1、100%和滚动条当我们在css中把html和body同时设为100%时&#xff0c;会出现滚动条html,body {width: 100%;height: 100%;}原因是html和body之间有8px的margin&#xff0c;这个margin怎么来的呢&#xff0c;我们在chrome中用F12看一下这个8px的margin来自于user agent stylesh…

小学生都能看懂的FFT!!!

小学生都能看懂的FFT&#xff01;&#xff01;&#xff01; 前言 在创新实践中心偷偷看了一天FFT资料后&#xff0c;我终于看懂了一点。为了给大家提供一份简单易懂的学习资料&#xff0c;同时也方便自己以后复习&#xff0c;我决定动手写这份学习笔记。 食用指南&#xff1a; …

ComboBox自动补全小技巧

网上看的自动补全实在是太麻烦&#xff0c;有时候还用到了第三方控件&#xff0c;但是现在我的需求是这样的 有一个Person类&#xff0c;其中有Code、Name两个属性 Person需要绑定到ComboBox中&#xff0c;在ComboBox中输入Code时&#xff0c;即自动补全相应的Name 想了半天&am…

可做fft分析吗_小吃店生意好做吗,小吃业行情分析

现在创业已经成为一种风尚&#xff0c;不少创业者都打算开一家小吃店&#xff0c;现在小吃店的生意好做吗&#xff1f;开小吃店有没有前景呢&#xff1f;中国人一直以来都非常看重“吃”&#xff0c;民以食为天&#xff0c;食物就是中国人生存的灵魂所在。基本上每个城市、每个…

ase加密放linux报错_Linux应用安装有福啦!和苹果Mac一样方便的单文件安装

自从用了苹果macbook&#xff0c;和windows基本上就再见了&#xff0c;苹果系统的稳定性太出色了&#xff0c;使用完合上盖子放十天半个月的没一点问题&#xff0c;一叫就醒&#xff0c;一醒就能接着工作&#xff0c;windows系统不行&#xff0c;要么睡了叫不醒&#xff0c;要么…

拼图展示

转载于:https://www.cnblogs.com/zm1994/p/8033332.html

c++全局监听ctrl s_号称史上最全!134个CAD快捷键强烈来袭,难道你只知道Ctrl+C?...

想要提高CAD绘图速率你就必须熟记CAD快捷键&#xff0c;小编盘点了134个CAD个快捷键&#xff0c;号称史上最全&#xff0c;一起来看看吧。一、常用字母键CO&#xff1a;复制MI&#xff1a;镜像AR&#xff1a;阵列O&#xff1a;偏移RO&#xff1a;旋转M&#xff1a;移动E&#x…

51nod 1623 完美消除(数位DP)

首先考虑一下给一个数如何求它需要多少次操作。 显然用一个单调栈就可以完成&#xff1a;塞入栈中&#xff0c;将比它大的所有数都弹出&#xff0c;如果栈中没有当前数&#xff0c;答案1。 因为数的范围只有0~9&#xff0c;所以我们可以用一个二进制数来模拟这个栈&#xff0c;…

代码 拉取_Git 利用 Webhooks 实现代码的自动拉取

WebHook 简介WebHook 功能是帮助用户 push 代码后&#xff0c;自动回调一个您设定的 http 地址。 这是一个通用的解决方案&#xff0c;用户可以自己根据不同的需求&#xff0c;来编写自己的脚本程序。环境服务器&#xff1a;ubuntuphp&#xff1a;7.2.28本文以拉取码云&#xf…

navicat连接mysql报10061错

可能原因&#xff1a;mysql服务未启动 解决办法&#xff1a;进入到计算机管理&#xff0c;找到服务&#xff0c;然后找到mysql服务&#xff0c;并启动该服务 转载于:https://www.cnblogs.com/mengyinianhua/p/8041201.html

长牙顺序

20个乳牙宝宝的诞生是有顺序的&#xff0c;虽然不一定一成不变&#xff0c;但是也可以作为参照的依据。 1.下乳中切牙 2.上乳中切牙 3.上乳侧切牙 4.下乳侧切牙 5.下第一乳磨牙 6.上第一乳磨牙 7.下乳尖牙 8.上乳尖牙 9.下第二乳磨牙 10.上第二乳磨牙 5~10个月&…