zoukankan      html  css  js  c++  java
  • 异步与同步委托,委托返回值

    异步委托,恰似一江春水向东流(你了解的异步委托)

       书是书,你是你,照抄文字那是书本的东西,你必须有你自己理解,就算是 有错误的认识。下面说下异步委托,个人涉 .net不深,经验尚浅,如果说的不对,希望大家指出来。
        对于线程,我不想多说了,可以搜索博客园 风尘浪子的  "线程上与线程下",说的相当详细。本篇博文就是针对:了解一些线程但对异步委托又模糊的朋友。
    其实这个异步委托,应该结合 线程Thread来一起讨论的,为什么我们现在对这个异步委托爱不释手,是因为它的3个原因:
    .不影响主线程的执行
    .合理的利用ThreadPool线程池的线程
    .异步委托本质是调用了线程池的工作者线程,不需要为了新建和注销线程烦恼,统一由线程池管理。

    1.传统的同步委托(模拟委托的方法执行时间很长)
    模拟委托的方法执行很长: Thread.Sleep(TimeSpan.FromSeconds(3));

    View Code
    //声明委托
    public delegate void DeleMethod(string name);
    class Program
    {
    static void Main(string[] args)
    {
    DeleMethod delemethod = Speaking;
    delemethod("Mr.w");
    Console.WriteLine("下面我还要执行方法....");

    }

    //要被委托调用的方法
    static void Speaking(string name)
    {
    Console.WriteLine("我的名字是:{0}",name);
    //利用休眠3秒钟,模拟委托执行的方法很长
    Thread.Sleep(TimeSpan.FromSeconds(3));
    Console.WriteLine("委托方法执行完毕!");
    }



    分析:
    .按F11大家都可以自己分析了,Main()是所有程序的开始,该程序调用Speaking()方法会休眠3秒,这样影响了主线程的下面的方法执行时间。
    .从头到尾,程序都只有一个线程,思考下:可不可以在利用一个子线程去帮我执行我的委托方法,不影响我的主线。
    答案是:可以,对于这种情况,我们可以 新建Thread类的线程,或者利用异步委托(线程池的工作者线程),这里我们不适用新建的线程,因为它不便于管理。

    2.初始异步委托

    View Code
    //声明委托
    public delegate void DeleMethod(string name);
    class Program
    {
    static void Main(string[] args)
    {
    DeleMethod delemethod = Speaking;
    //执行异步委托
    delemethod.BeginInvoke("Mr.w",null,null);
    //主线程方法
    Console.WriteLine("下面我还要执行方法....");

    }

    //要被委托调用的方法
    static void Speaking(string name)
    {
    Console.WriteLine("我的名字是:{0}",name);
    //利用休眠3秒钟,模拟委托执行的方法很长
    Thread.Sleep(TimeSpan.FromSeconds(3));
    Console.WriteLine("委托方法执行完毕!");
    }
    }
    输出:
    下面我还要执行方法....
    我的名字是:Mr.w




    分析:
    1.怎么回事?怎么好像 委托方法没有执行完毕?
    答:线程分为:前台线程和后台线程,默认线程池的都是后台线程,主线程是不会管 后台线程是否执行完毕,就直接退出程序。新建的Thread类的线程默认是前台线程,主线程必须等待他执行完毕再退出AppDomain.
    是否是前台或者后台线程取决于:IsBackground属性。
    2.我们利用一个Console.ReadKey();可以让主线程不退出AppDomain。


    3.说一说带返回值的异步委托
    大家都知道,有时候,主线程根本就不关心 委托方法的返回值,所以是否能把 异步委托的返回值 显示在我的主窗口就更不关心了,但是返回值 也是可以解决很多问题的:
    1.上篇博文已经提及了,非void委托方法可以返回  异常信息
    2.有些软件需要 把委托方法的返回值 作为另一个方法的参数来处理

    代码1:
     

    View Code
    //声明委托
    public delegate string DeleMethod(string name);
    class Program
    {
    static void Main(string[] args)
    {
    DeleMethod delemethod = Speaking;
    //执行异步委托
    IAsyncResult result=delemethod.BeginInvoke("Mr.w",null,null);
    string s=delemethod.EndInvoke(result);
    //主线程方法
    Console.WriteLine("下面我还要执行方法....");
    //阻止主线程退出程序
    Console.ReadKey();
    }

    //要被委托调用的方法
    static string Speaking(string name)
    {
    //利用休眠3秒钟,模拟委托执行的方法很长
    Thread.Sleep(TimeSpan.FromSeconds(3));
    Console.WriteLine("我的名字是:{0}", name);
    return "委托方法执行完毕!";
    }
    }
    输出:
    我的名字是:Mr.w
    下面我还要执行方法....



    注意:
    看输出的结果,按照我们的理论,应该输出结果是:

    下面我还要执行方法....
    我的名字是:Mr.w

    怎么结果相反了?
    答案:
    1.因为异步委托  由 BeginInvoke()方法开始,以EndInvoke()结束。
    2.异步委托的返回值是由 EndInvoke();返回的。

    所以:你如果想要返回值,必须写EndInvoke();,可是有人要问了,如果在主线程调用EndInvoke()方法,主线程不是要等待 子线程执行完毕之后才 会执行下面的代码,这和  同步执行有什么区别?那异步就没有意义了。

    正确!完全正确,但是有没有 又可以得到异步委托的结果,又不影响主线程的方式。

    4.说一说 得到返回值,又不影响主线程的方式

    解决这个问题,必须了解下,异步委托的BeginInvoke()方法

    1.BeginInvoke()最容易被忘记的是:执行BeginInvoke()方法的委托变量,如上面的:delemethod变量必须是单播委托,也就是说只能绑定一个方法。对于多播委托,请把所有方法遍历出来在使用异步委托,如何遍历查询我的上一篇博文。
    2.BeginInvoke()方法有4个参数,前2个是和你的委托方法的参数一致的,后2个参数,分别是AsyncCallback类型和Object类型,其中AsyncCallback是一个委托类型,它用于当异步执行完毕时自动进行调用的方法,最后一个参数Object类型可以通过 AsyncResult类型变量的AsyncState属性获得,或者 IAsyncResult类型变量的AsyncState属性
    3.BeginInvoke()方法 返回值是 一个IAsyncResult接口,实质就是AsyncResult的对象。通过AsyncResult的AsyncDelegate获得delemthod委托对象,然后再在其上调用EndInvoke()方法。

    是不是越来越迷糊,结合案例看:
    代码1:

    View Code
    输出:
    下面我还要执行方法....
    我的名字是:Mr.w
    委托方法执行完毕!



    先看结果:结果是符合我们的理论的。
    分析:
    1.大家都知道异步委托要想有返回值,必须调用EndInvoke()方法,但是用哪个委托变量调用呢?
    .BeginInvoke()方法最后一个参数就是 BeginInvoke()返回值的IAsyncResult类型变量的AsyncState,这样获取委托变量的对象,如代码1
    .或者通过AsyncResult的AsyncDelegate获得delemethod委托对象,然后再在其上调用EndInvoke()方法。如代码2
    代码2:
     

    View Code
    输出:
    当前线程ID:1
    下面我还要执行方法....
    当前线程ID:3
    我的名字是:Mr.w
    当前线程ID:3
    委托方法执行完毕!
    当前线程ID:3




    总结:异步委托先介绍到这里,具体的应用还要看你对线程的理解,有时候同步比异步快。有时候异步比同步块,由具体情况决定。

  • 相关阅读:
    踩坑纪录——Lombok加Builder注解后mybatis无法识别字段正确类型
    安装node
    PostgreSQL DISTINCT ON
    RabbitMQ安装到使用入门
    springboot整合rabbitMQ时遇到的消息无法入列问题
    不同版本springboot上传文件大小设置
    thymeleaf报错元素类型必须由匹配的结束标记终止
    不同版本springboot端点开启方法
    mybatis匹配字符串的坑
    杂记
  • 原文地址:https://www.cnblogs.com/sishahu/p/2349468.html
Copyright © 2011-2022 走看看