zoukankan      html  css  js  c++  java
  • C#:同步调用、异步调用、异步回调

    ylbtech-C#:同步调用、异步调用、异步回调
    1.返回顶部
    1、

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

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


        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(1, 2);

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

                Console.WriteLine(result);
                Console.ReadKey();
            }
            
    }

    同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量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(1, 2, null, null);

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

                //异步操作返回
                Console.WriteLine(handler.EndInvoke(result));
                Console.ReadKey();
            }
            
    }

    可以看到,主线程并没有等待,而是直接向下运行了。
    但是问题依然存在,当主线程运行到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);
            }
            
    }

    我定义的委托的类型为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)); 
          。。。。。
    }

    完整代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Remoting.Messaging;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ThreadCallback
    {
        class Program
        {
    
            public delegate int AddHandler(int a, int b, int c);
    
            public class AddClass
            {
                public static int Add(int a, int b, int c)
                {
                    Console.WriteLine("
    开始计算:" + a + "+" + b + "+"+c);
                    Thread.Sleep(3000); //模拟该方法运行三秒
                    Console.WriteLine("计算完成!");
                    return a + b + c;
                }
            }
    
            /// <summary>
            /// 同步调用
            /// </summary>
            public class SynchronousCall
            {
                static void Main_S()
                {
                    Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
                    AddHandler handler = new AddHandler(AddClass.Add);
                    int result = handler.Invoke(1, 2, 3);
    
                    Console.WriteLine("继续做别的事情。。。");
    
                    Console.WriteLine(result);
                    Console.ReadKey();
                }
    
            }
    
            /// <summary>
            /// 异步调用
            /// </summary>
            public class AsynchronousCall
            {
                static void Main_S()
                {
                    Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
                    AddHandler handler = new AddHandler(AddClass.Add);
    
                    //IAsyncResult: 异步操作接口(interface)
                    //BeginInvoke: 委托(delegate)的一个异步方法的开始
                    IAsyncResult result = handler.BeginInvoke(1, 2,3, null, null);
                    Console.WriteLine("------继续做别的事情。。。
    ");
    
                    //异步操作返回
                    Console.WriteLine(handler.EndInvoke(result));
                    Console.ReadKey();
                }
    
            }
    
    
            static void Main(string[] args)
            {
    
                Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
                AddHandler handler = new AddHandler(AddClass.Add);
    
                //异步操作接口(注意BeginInvoke方法的不同!)
                IAsyncResult result = handler.BeginInvoke(1, 2,3, new AsyncCallback(CallbackFunc), "AsycState:OK");
    
                Console.WriteLine("------继续做别的事情。。。--------");
                Console.ReadKey();
    
            }
    
            static void CallbackFunc(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);
            }  
    
        }
    }
    2、
    2.返回顶部
    1、多线程回调传值例子|C#多线程回调传值例子
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    using System;
    using System.Threading;
    namespace DataImportFromAccess
    {
    
    
        //声明一个回调函数:注意传递的参数要与Example类中的函数参数类型一致
        public delegate void ExampleCallback(int lineCount, Label lb);
        public class Form1{
            public Form1()
            {
                InitializeComponent();
            }
    
            public void CurrentNumber(int tempCurrent,Label lb)
            {
                lb.Text = tempCurrent.ToString();
            }
            private void button1_Click(object sender, EventArgs e)
            {
                ThreadWithData twd = new ThreadWithData(1, 100,this.label1,new ExampleCallback(CurrentNumber));
                Thread td = new Thread(new ThreadStart(twd.RunMethod));
                td.Start();
            }   
            private void button2_Click(object sender, EventArgs e)
            {
                ThreadWithData twd = new ThreadWithData(2, 200,this.label2, new ExampleCallback(CurrentNumber));
                Thread td = new Thread(new ThreadStart(twd.RunMethod));
                td.Start();
            }
        }
        public class ThreadWithData
        {
            private int start = 0;
            private int end = 0;
            private ExampleCallback callBack;
            private Label lb;
    
            public ThreadWithData(int start,int end,Label lb,ExampleCallback callBack)
            {
                this.start = start;
                this.end = end;
                this.callBack=callBack;
                this.lb = lb;
            }
            public void RunMethod()
            {
                for(int i=start;i<end;i++)
                {
                    Thread.Sleep(1000);
                    if (callBack != null)
                        callBack(i,lb);
                }
             
            }
        }
    }
    2、
    3.返回顶部
     
    4.返回顶部
     
    5.返回顶部
     
     
    6.返回顶部
     
    warn 作者:ylbtech
    出处:http://ylbtech.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    【HTML5 绘图与动画】使用canvas
    【H5新增元素和文档结构】新的全局属性 1. contentEditable 可编辑内容 2. contextmenu 快捷菜单 3. data 自定义属性 4. draggable 可拖动 5. dropzone 拖动数据 6. hidden 隐藏 7. spellcheck 语法检查 8. translate 可翻译
    【H5新增元素和文档结构】完善旧元素 1. a 超链接 2. ol 有序列表 3. dl 定义列表 4. cite 引用文本 5. small 小号字体 6. iframe 浮动框架 7. script 脚本
    【H5新增元素和文档结构】新的语义信息 1. address 2. time 3. figure 跟 figcaption 4. details 和 summary 5. mark 6. progress 7. meter 8. dialog 9.bdi 10. wbr 11. ruby、rt、rp 12. command
    【H5新增元素跟文档结构】新的文档结构 1. article 文章块 2. section 区块 3. nav 导航条 4. aside 辅助栏 5. main 主要区域 6. header 标题栏 7. hgroup 标题组 8. footer 页脚栏
    5_PHP数组_3_数组处理函数及其应用_9_数组集合运算函数
    【华为云技术分享】鲲鹏弹性云服务器GCC交叉编译环境搭建指南
    【华为云技术分享】7 分钟全面了解位运算
    【华为云技术分享】Linux内核编程环境 (1)
    【华为云技术分享】华为云MySQL 8.0正式商用,全新增强版开源利器强势来袭
  • 原文地址:https://www.cnblogs.com/storebook/p/12151465.html
Copyright © 2011-2022 走看看