zoukankan      html  css  js  c++  java
  • CSharp 使用委托实现的同步调用,异步调用,异步回调

    CSharp 使用委托实现的同步调用,异步调用,异步回调


    下面我们将通过代码的例子来描述,同步调用,异步调用,异步回调的应用场景.

    public delegate int AddHandler(int a,int b)
    
    public class AddClass
    {
    
    	public ststic int AddFanc(int a,int b)
    	{
    		Console.WriteLine($"开始计算:{a}+{b}");
    		Thread.Sleep(3000);  //假定此方法是一个耗时方法
    		Console.WriteLine("计算完成");
    	}
    }

    同步调用

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

    public class 同步调用
    {
     	static void Main()
     	{
     		Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
     		AddHandler handler = new AddHandler(加法类.Add);
     		int result = handler.Invoke(1, 2);
     		Console.WriteLine("继续做别的事情。。。");
     		Console.WriteLine(result);
     		Console.ReadKey();
     	}
    }

    我们可以观察到主线程被阻塞了3秒,如果我们要进行一项繁重的操作,使用同步调用的方式,来调用耗时方法,将会造成很严重的性能问题,比如页面卡死等,这个时候就有必要使用到异步调用的概念了.

    异步调用

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

    public class 异步调用
    {
     	static void Main()
     	{
     		Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
     		AddHandler handler = new AddHandler(加法类.Add);
     		//IAsyncResult: 异步操作接口(interface)
    		//BeginInvoke: 委托(delegate)的一个异步方法的开始
     		IAsyncResult result = handler.BeginInvoke(1, 2, null, null);
    	    Console.WriteLine("继续做别的事情。。。");
     		//异步操作返回
     		Console.WriteLine(handler.EndInvoke(result));
     		Console.ReadKey();
     	 }
    }

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

    异步委托,也可以使用下面的写法:

    Action<object> action = (obj)=>
    { 
       //耗时方法体
       Thread.Sleep(3000);
       return true;
    };
    
    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);
    	 }
     
    }

    异步回调总结

    • int result = handler.Invoke(1,2);为什么Invoke的参数和返回值和AddHandler委托是一样的呢?

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

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

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

    • IAsyncResult.AsyncState 属性:
      获取用户定义的对象,它限定或包含关于异步操作的信息,例如:
    static void AddComplete(IAsyncResult result) 
    { 
    	AddHandler handler = (AddHandler)result.AsyncState; 
    	Console.WriteLine(handler.EndInvoke(result)); 
    }

    如果需要更进一步的了解,可参考:
    C#基础:线程之前的异步调用(委托方式)
    使用回调从一个线程中检索数据

  • 相关阅读:
    670. Maximum Swap
    653. Two Sum IV
    639. Decode Ways II
    636. Exclusive Time of Functions
    621. Task Scheduler
    572. Subtree of Another Tree
    554. Brick Wall
    543. Diameter of Binary Tree
    535. Encode and Decode TinyURL
    博客园自定义背景图片
  • 原文地址:https://www.cnblogs.com/HelloZyjS/p/12613381.html
Copyright © 2011-2022 走看看