C# 多线程系列之异步回调(委托)

本文参考自C#基础:线程之异步回调(委托),纯属读书笔记

在解析异步回调之前,先看同步回调的执行过程,以及代码原理。

1、线程的同步执行

同步执行:在主线程执行的时候,主线程调用一个其它方法,此时主线程阻塞,等待调用方法执行完成后主线程才能继续执行。

代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i < 11; i++) {
                if (i == 5) {
                    Console.WriteLine("调用TakeAWhile方法并等待其执行完成");
                    Console.WriteLine("开始执行TakeAWhile方法,时间:{0}", DateTime.Now);
                    int result = TakeAWhile(0, 6000);
                    if (result == 1) {
                        Console.WriteLine("TakeAWhile方法执行完成");
                    }
                    Console.WriteLine("TakeAWhile方法执行完毕,时间:{0}", DateTime.Now);
                }
                Thread.Sleep(30);
                Console.WriteLine(i.ToString());
            }
        }
        static int TakeAWhile(int data, int time) {
            Thread.Sleep(time);
            return ++data;
        }
    }

从上面的结果得出当程序开始调用TakeAWhile方法后,主线程阻塞,当TakeAWhile方法调用完毕之后,主线程又重新开始运行,这个过程就是线程的同步执行的过程.

2、线程的异步执行

what is 异步执行?

异步执行:在主线程执行的时候,打开一个子线程,主线程不会像同步执行的那样等待子线程的结果返回后在执行,主线程会继续执行,当主线程需要子线程的运行结果时,主线程直接调用子线程的运行结果,如果子线程的运行结果还没有出来,那么主线程等待,直到子线程执行结束,主线程拿到子线程的运行结果,主线程在继续。

 class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> fun = TakeAWhile;
            IAsyncResult ar = fun.BeginInvoke(0, 1000, null, null);//主线程调用子线程开始执行TakeAWhile方法,并给它传递了参数
            int times=1;
            while (!ar.IsCompleted)
            {
                //当子线程没有完成之前,主线程可以在该while语句块内进行任何后续操作,而且不用等待子线程的结束
                Console.WriteLine(times++);
                Thread.Sleep(50);
            }
            int result = fun.EndInvoke(ar);//1秒之后我需要子线程的结果了,ok,从子线程中拿到结果
            Console.WriteLine("TakeAWhile方法结束,时间是:{0}", DateTime.Now);
            Console.WriteLine("result:{0}", result);
            Console.ReadKey();
        }

        static int TakeAWhile(int data, int times)
        {
            Console.WriteLine("TakeAWhile方法开始执行,时间是:{0}",DateTime.Now);
            Thread.Sleep(times);
            return ++data;
        }
    }

从结果和代码进行分析,当通过BeginInvoke方法开始异步执行TakeAWhile方法,主线程继续执行,然后通过IsCompleted属性判断TakeAWhile是否执行完成,最后获取子线程的输出值,并输出其结果,整个过程主线程没有因为在执行子线程的原因,而造成阻塞

 注:

因为多线程,导致了这个情况,开启子线程和执行子线程中的方法都需要时间,所以主线程的执行速度快于子线程,所以先输出了一个1;解决方法很简单,让主线程休息一会,等子线程先初始化完,代码如下:

class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> fun = TakeAWhile;
            IAsyncResult ar = fun.BeginInvoke(0, 1000, null, null);//主线程调用子线程开始执行TakeAWhile方法,并给它传递了参数
            Thread.Sleep(30);//休息一会
            int times=1;
            while (!ar.IsCompleted)
            {
                //当子线程没有完成之前,主线程可以在该while语句块内进行任何后续操作,而且不用等待子线程的结束
                Console.WriteLine(times++);
                Thread.Sleep(50);
            }
            int result = fun.EndInvoke(ar);//6秒之后我需要子线程的结果了,ok,从子线程中拿到结果
            Console.WriteLine("TakeAWhile方法结束,时间是:{0}", DateTime.Now);
            Console.WriteLine("result:{0}", result);
            Console.ReadKey();
        }

        static int TakeAWhile(int data, int times)
        {
            Console.WriteLine("TakeAWhile方法开始执行,时间是:{0}",DateTime.Now);
            Thread.Sleep(times);
            return ++data;
        }
    }

3、异步回调

what is 异步异步回调?

异步回调:主线程在执行的时候,打开一个子线程,主线程继续执行,当子线程执行完成的时候,主线程立即输出子线程的运行结果,主线程继续执行。

class Program
    {
        static void Main(string[] args)
        {
            Func<int, int, int> fun = TakeAWhile;
            fun.BeginInvoke(0, 1000, TakesAWhileCallBack, fun);//异步调用TakeAWhile,并指定回调函数TakesAWhileCallBack
            for (int i = 0; i < 20; i++)
            {
                Console.WriteLine(i.ToString());
                Thread.Sleep(100);
            }
            Console.ReadKey();
        }
        static int TakeAWhile(int data, int times) {
            Console.WriteLine("TakeAWhile方法开始执行,时间是:{0}", DateTime.Now);
            Thread.Sleep(times);
            return ++data;
        }
        /// <summary>
        /// 回调函数
        /// </summary>
        /// <param name="fun">调用的委托</param>
        static void TakesAWhileCallBack(IAsyncResult fun)
        {
            if (fun == null)
                throw new ArgumentNullException("fun");
            Func<int, int, int> dl = (Func<int, int, int>)fun.AsyncState;
            int result = dl.EndInvoke(fun);
            Console.WriteLine("我是回调函数返回的结果:{0}", result);
            Console.WriteLine("TakeAWhile执行完成,时间是:{0}", DateTime.Now);
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏待你如初见

Java爬虫及分布式部署

36050
来自专栏菩提树下的杨过

redis 学习笔记(7)-cluster 客户端(jedis)代码示例

上节学习了cluster的搭建及redis-cli终端下如何操作,但是更常用的场景是在程序代码里对cluster读写,这需要redis-client对clust...

23180
来自专栏大内老A

[WCF REST] WebServiceHost有何特别之处?

WCF为REST服务的寄宿提供了一个新的ServiceHost,即WebServiceHost。WebServiceHost是ServiceHost的子类,而W...

22560
来自专栏大内老A

我的WCF之旅(5):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的重载(Overloading)

对于.NET重载(Overloading)——定义不同参数列表的同名方法(顺便提一下,我们但可以在参数列表上重载方法,我们甚至可以在返回类型层面来重载我们需要的...

28960
来自专栏大内老A

像TransactionScope一样使用DbTransaction

System.Transactions.TransactionScope为了提供一种非常方便的实现分布式事务的方式,但是在某些情况下为了阻止本地事务向分布式事务...

53070
来自专栏GreenLeaves

Linq基础知识之延迟执行

Linq中的绝大多数查询运算符都有延迟执行的特性,查询并不是在查询创建的时候执行,而是在遍历的时候执行,也就是在enumerator的MoveNext()方法被...

258100
来自专栏跟着阿笨一起玩NET

关于DataGridView_DataError事件的问题

本文转载:http://blog.csdn.net/szstephenzhou/article/details/7834725

45110
来自专栏Java成神之路

Java微信公众平台开发_05_微信网页授权

登录微信公众平台后台, 开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息 - 修改,

1.5K30
来自专栏hbbliyong

依赖注入(IOC)

背景介绍 在设计模式中,尤其是结构型模式很多时候解决的就是对象间的依赖关系,变依赖具体为依赖抽象。平时开发中如果发现客户程序依赖某个或某类对象,我们常常会对他...

28940
来自专栏Java进阶架构师

03:SpringBoot整合SpringDataJPA实现数据库的访问(二)

首先回忆一下,前面我们创建studentRepo类继承JpaRepository<T,ID>接口,即可实现最基本的crud。如下:

9920

扫码关注云+社区

领取腾讯云代金券