[转载]C#异步委托的用法 .

每个委托都有三个方法:Invoke、BeginInvoke、EndInvoke。第一个方法是委托指定函数的同步调用,另外两个是异步调用。

        BeginInvoke方法,调用后立即返回,不等待调用结果。EndInvoke方法,用于检索调用结果。调用BeginInvoke后可随时调用 EndInvoke 方法;如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。EndInvoke 的参数包括您需要异步执行的方法的 out 和 ref 参数(在 Visual Basic 中为 <Out> ByRef 和 ByRef)以及由 BeginInvoke 返回的 IAsyncResult

        BeginInvoke 异步方法签名的规则是:

  • 包括所有 IN 参数。

  • 包括所有 OUT 参数。

  • 包括所有 IN/OUT 参数。

  • 包括所有 ByRef 参数。

  • 将 AsyncCallback 和 AsyncState(可通过 IAsyncResult 接口的 AsyncState 属性获得)作为最后两个参数。

  • 返回 IAsyncResult。

        EndInvoke 异步方法签名的规则是:

  • 包括所有 IN/OUT 参数。

  • 包括所有 OUT 参数。

  • 包括所有 ByRef 参数。

  • 将 IAsyncResult 作为最后一个参数。

  • 从原始方法签名返回原始返回类型。

        结果对象 (IAsyncResult) 是从开始操作返回的,并且可用于获取有关异步开始操作是否已完成的状态。结果对象被传递到结束操作,该操作返回调用的最终返回值。在开始操作中可以提供可选的回调。如果提供回调,在调用结束后,将调用该回调;并且回调中的代码可以调用结束操作。


AsyncCallback 委托

        AsyncCallback 委托用于指定在开始操作完成后应被调用的方法。下面是该委托的签名,AsyncCallback 委托被作为开始操作上的第二个到最后一个参数传递:

        public delegate void AsyncCallback(IAsyncResult ar);

IAsyncResult 接口

        IAsyncResult 接口用于监视和管理异步操作。该接口是从开始操作返回的并被传递到结束操作,以将开始操作和结束操作相关联。如果回调被指定为开始操作的一部分,则 AsyncResult 被传递到回调。以下代码阐释有关 IAsyncResult 接口的属性,该接口可用于监视异步操作的状态并获取还可被传递到开始操作中的异步状态对象:


public interface IAsyncResult

{

  Object AsyncState { get; }                       //该属性为BeginInvoke参数中的最后一个参数对象

  WaitHandle AsyncWaitHandle { get; }

  bool CompletedSynchronously { get; }

  bool IsCompleted { get; }                         //该属性判断异步调用是否结束

}

  • AsyncState

        返回在开始操作方法调用中作为最后一个参数提供的对象。

  • AsyncWaitHandle

        AsyncWaitHandle 属性返回 WaitHandle,后者可用于执行 WaitHandle.WaitOne、WaitAny 或 WaitAll。

        注意   直到 AsyncWaitHandle 属性被读取时,实现 IAsyncResult 的对象才需要创建 WaitHandle;执行时间由实施者决定。如果实施者创建了 WaitHandle,则实施者需要负责在适当的时候发出 WaitHandle 信号终止等待。例如,当异步调用的方法返回时,AsyncResult 将代表调用方终止等待。创建后,WaitHandle 应保持活动状态,直到用户调用结束异步操作的方法。此时,可以丢弃 AsyncWaitHandle 后的对象。

  • CompletedSynchronously

        如果开始操作调用已同步完成,则 CompletedSynchronously 属性将被设置为 true。

  • IsCompleted

        在服务器已处理完调用后,IsCompleted 属性将被设置为 true。

        调用了 BeginInvoke 后,可以:

  • 进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。

  • 使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke。

  • 轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke。

  • 将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。

        注: 始终在异步调用完成后调用 EndInvoke。

        以下是关于异步委托的测试代码:

using System;

using System.Threading;

 

public class AsyncDemo {

    // The method to be executed asynchronously.

    //

    public string TestMethod(int callDuration, out int threadId) {

        Console.WriteLine("Test method begins.");

        Thread.Sleep(callDuration);

        threadId = AppDomain.GetCurrentThreadId();

        return "MyCallTime was " + callDuration.ToString();

    }

}

 

// The delegate must have the same signature as the method

// you want to call asynchronously.

public delegate string AsyncDelegate(int callDuration, out int threadId);

 

public class AsyncMain {

    static void Main(string[] args) {

        // The asynchronous method puts the thread id here.

        int threadId;

 

        // Create an instance of the test class.

        AsyncDemo ad = new AsyncDemo();

 

        // Create the delegate.

        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);

  

        // Initiate the asychronous call.

        IAsyncResult ar = dlgt.BeginInvoke(3000,

            out threadId, null, null);

 

        Thread.Sleep(0);

        Console.WriteLine("Main thread {0} does some work.",

            AppDomain.GetCurrentThreadId());

 

        // Wait for the WaitHandle to become signaled.

        ar.AsyncWaitHandle.WaitOne();

/*              
这个是轮询异步执行状态

        // Poll while simulating work.

        while(ar.IsCompleted == false)

        {

            Thread.Sleep(10);

        }

*/

        // Call EndInvoke to Wait for the asynchronous call to complete,

        // and to retrieve the results.

        string ret = dlgt.EndInvoke(out threadId, ar);

 

        Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, ret);

    }

}

 

        以下代码是用回调函数执行EndInvoke方法

public class AsyncMain {

    // Asynchronous method puts the thread id here.

    private static int threadId;

 

    static void Main(string[] args) {

        // Create an instance of the test class.

        AsyncDemo ad = new AsyncDemo();

 

        // Create the delegate.

        AsyncDelegate dlgt = new AsyncDelegate(ad.TestMethod);

  

        // Initiate the asychronous call.  Include an AsyncCallback

        // delegate representing the callback method, and the data

        // needed to call EndInvoke.

        IAsyncResult ar = dlgt.BeginInvoke(3000,

            out threadId,

            new AsyncCallback(CallbackMethod),

            dlgt );

 

        Console.WriteLine("Press Enter to close application.");

        Console.ReadLine();

    }

   

        

    // Callback method must have the same signature as the

    // AsyncCallback delegate.

    static void CallbackMethod(IAsyncResult ar) {

        // Retrieve the delegate.

        AsyncDelegate dlgt = (AsyncDelegate) ar.AsyncState;

 

        // Call EndInvoke to retrieve the results.

        string ret = dlgt.EndInvoke(out threadId, ar);

 

        Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", threadId, ret);

    }

}

-----------------------------------------------------------------------

 

当进行耗时的工作时,可以使用异步委托执行。

view sourceprint?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
  
namespace 线程
{
    class Program
    {
        delegate int facHandler(int n);
        static int Fac(int n)
        {
            if (n == 1)
                return 1;            
            System.Threading.Thread.Sleep(100);           
            return Fac(n - 1) * n;
        }
  
        static void callBack(IAsyncResult result)
        {
            //result是Fac()的返回值            
            //将AsyncDelegate强制转换为用户定义的委托。
            facHandler handler = (facHandler)((AsyncResult)result).AsyncDelegate;
            Console.WriteLine("结果:" + handler.EndInvoke(result));
            Console.WriteLine(result.AsyncState);
        }
  
        static void Main(string[] args)
        {
            facHandler f = new facHandler(Fac);
            //开异步方法开始执行
            IAsyncResult result = f.BeginInvoke(10, new AsyncCallback(callBack), "计算结束");
            Console.WriteLine("做其他事情先……");
            Console.Read();
        }
    }
}

 ---------------------------------------------------------------

 

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)); 
      。。。。。
}

 

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

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

相关文章

sqlite3的基本操作

转自&#xff1a;http://blog.chinaunix.net/uid-26833883-id-3239313.html一、数据库基本概念 A.数据(Data)能够输入计算机并能被计算机程序识别和处理的信息集合。B.数据库(Database)数据库是在数据库管理系统管理和控制之下&#xff0c;存放在存储介质上的数据集合。注意&am…

收藏这些芯片原厂的代码仓库

本次给大家分享一些芯片原厂的代码仓库&#xff0c;这些资源已收录到咱们嵌入式大杂烩的资源仓库里了&#xff1a;https://gitee.com/zhengnianli/EmbedSummary我们用到一个新的芯片时&#xff0c;一般在它们的官网都可以找到一些入门、上手的资料。除此之外&#xff0c;有些原…

javascript计算小数保留两位小数,多位小数的方法

<SCRIPT LANGUAGE"JavaScript"><!--functionformatFloat(src, pos){ return Math.round(src*Math.pow(10, pos))/Math.pow(10, pos);}alert(formatFloat("1212.2323", 2));//--></SCRIPT>转载于:https://www.cnblogs.com/catxp/archi…

Android dumpsys命令详细使用

Android dumpsys命令详细使用 一、dumpsys命令介绍 1.命令说明 Dumpsys用户系统诊断&#xff0c;它运行在设备上&#xff0c;并提供系统服务状态信息 命令格式&#xff1a; adb shell dumpsys [system serbices] 2.系统服务查询 如果直接运行adb shell dumpsys&#xff0c;将会…

qemu+linux+x86+64,qemu以64位跟32位的方式跑busybox

qemu以64位和32位的方式跑busybox两种方式x86_64 和32位的i386方式-----------x86_64-----------------------------------------参考http://mgalgs.github.io/2015/05/16/how-to-build-a-custom-linux-kernel-for-qemu-2015-edition.html下载busybox和linux内核TOP/var/www/my…

基于 esp32 + lvgl8.0 的小电视

一个有趣的作品&#xff0c;转给需要的小伙伴。详情可阅读&#xff1a;https://gitee.com/wangpeng25/the-little-bili-tv输入图片说明支持功能微信配网&#xff08;完成&#xff09;时间显示&#xff08;完成&#xff09;三日天气显示&#xff08;完成&#xff09;温湿度显示&…

Android中常见的MVC/MVP/MVVM模式

Android中常见的MVC/MVP/MVVM模式 经典MVC 在1979年&#xff0c;经典MVC模式被提出。 在当时&#xff0c;人们一直试图将纯粹描述思维中的对象与跟计算机环境打交道的代码隔离开来&#xff0c;而Trygve Reenskaug在跟一些人的讨论中&#xff0c;逐渐剥离出一系列的概念&#xf…

同步滚动两个DataGrid

拿到这个首先想到的就是重写Scroll方法&#xff0c;可是想想工作量有些大&#xff0c;所以想在Form级别上做做手脚&#xff0c;看看DataGrid的成员列表可以看到这样两个保护性的方法&#xff1a;GridHScrolled Listens for the horizontal scrollbars scroll even…

RISC-V踩坑记----__builtin_clz((x)库函数的应用

RISC-V的确是个好东西&#xff0c;可是&#xff0c;免费的东西往往需要付出代价才能得到了&#xff0c;最近遇到了一个算法中的问题&#xff0c;追了好久&#xff0c;最终追到了这个库函数中&#xff0c;没想到&#xff0c;这个库函数居然还隐藏着一些猫腻。值得记下来啊。 首先…

整蛊偷快递的家伙!不愧是 NASA 工程师

分享个有意思的新闻给大家&#xff0c;一笑之余&#xff0c;也可以学习下文中主角的理工科思维。不知道你有木有过。。快递包裹被别人偷走的经历&#xff1f;&#xff1f;包裹历经波折终于到了家门口&#xff0c;结果。。却被人给顺走了&#xff01;&#xff01;报警&#xff1…

dns 320 linux,linux 下 dns服务器(三 配置篇)

如何设置一个caching only域名服务器1 设置所谓caching only域名服务器是指一个服务器运行有n a m e d进程&#xff0c;但是并不对任何域(区)的域名信息具有授权&#xff0c;也就是并不向外提供本域的域名匹配信息&#xff0c;不负责I n t e r n e t上对本组织域名解析的应答&…

图解Cisco Packet Tracert之利用TFTP来升级路由器的IOS

对于我们这些学生来说&#xff0c;如果是自学的朋友来说&#xff0c;想摸到真机那实在是太难了&#xff0c;说去买一台呢&#xff1f;买来又没有多大作用&#xff0c;利用dynamips来模拟呢&#xff0c;他本来就是加载的IOS&#xff0c;在flash里面又没有IOS&#xff0c;这时候那…

终于用上gcc-4.1编译的系统了

终于用上gcc-4.1编译的系统了 把PHP、APACHE2、MYSQL又配好了。数据还是原来的数据。posted on 2006-05-19 07:35 浙林龙哥 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/huqingyu/archive/2006/05/19/403972.html

Android中的动画有哪几类?各自的特点和区别是什么?

在 android.view.animation包中有四种基本的动画 &#xff0c;透明&#xff0f;伸缩&#xff0f;移动&#xff0f;旋转。动画类型Android的animation由四种类型组成XML中alpha渐变透明度动画效果scale渐变尺寸伸缩动画效果translate画面转换位置移动动画效果rotate画面转移旋转…

不指导,一起学习

不敢说指导&#xff0c;只能说以自己的观点来说下这个事情。年前的时候&#xff0c;我一个朋友的朋友也想学电子方面的技术&#xff0c;他毕业后做汽修工作&#xff0c;但是没做多久没离职了&#xff0c;之后在工厂上班一段时间&#xff0c;最近两年帮亲戚一起打理一些生意上的…

linux按键检测结束,关于Linux下按键的检测

写这篇博客是因为自己想做一个fc模拟器&#xff0c;核心代码(6502和ppu的模拟代码)用的原子开发板的代码&#xff0c;人家是从pc向单片机移植&#xff0c;我是反过来了&#xff0c;不过因为写的不错&#xff0c;用函数指针代替了switch方法可以学习一下&#xff0c;so就用了它的…

(翻译)Tricks of the windows game programming Gurus(Windows游戏大师之路) --- 前言(作者:ANDRE LAMOTHE 1999)...

前言&#xff1a;在一篇零编程学习游戏编程的文章文章中提及此书&#xff0c;而且书评很不错&#xff0c;在当时反响很剧烈。因此下了个PDF版的慢慢学习。虽然接触游戏编程很久&#xff0c;玩的五花八门的游戏也有很多&#xff0c;但真正完成的游戏只有一个扫雷游戏。文章中建议…

C语言那年踩过的坑--局部变量,静态变量,全局变量在内存中存放的位置

先看几个概念&#xff1a; 1、bss是英文block started by symbol的简称&#xff0c;通常是指用来存放程序中未初始化的全局变量的一块内存区域&#xff0c;在程序载入时由内核清0。bss段属于静态内存分配。它的初始值也是由用户自己定义的连接定位文件所确定&#xff0c;用户应…

如何阅读3,500万个博客?

博客至今已经出现5年了&#xff0c;目前这股热潮正在愈演愈烈。博客又叫网络日志&#xff0c;现在已经非常普及&#xff1b;跟踪3,500多万个博客的Technorati Inc.称&#xff0c;博客的总数量每6个月就增加一倍。这就带来了一个问题&#xff1a;如何从浩如烟海的信息中找到想要…

u-boot与bootloader及其区别

Bootloader比Bootloader从字面上来看就是启动加载的意思。用过电脑的都知道&#xff0c;windows开机时会首先加载bios&#xff0c;然后是系统内核&#xff0c;最后启动完毕。那么bootloader就相当于手机的bios&#xff0c;它在手机启动的时候根据基带初始化硬件&#xff0c;然后…