博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET异步编程之回调
阅读量:4558 次
发布时间:2019-06-08

本文共 5856 字,大约阅读时间需要 19 分钟。

C#中异步和多线程的区别是什么呢?异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性。甚至有些时候我们就认为异步和多线程是等同的概念。但是,异步和多线程还是有一些区别的。而这些区别造成了使用异步和多线程的时机的区别。  

  异步操作的本质

  所有的程序最终都会由计算机硬件来执行,所以为了更好的理解异步操作的本质,我们有必要了解一下它的硬件基础。 熟悉电脑硬件的朋友肯定对DMA这个词不陌生,硬盘、光驱的技术规格中都有明确DMA的模式指标,其实网卡、声卡、显卡也是有DMA功能的。DMA就是直 接内存访问的意思,也就是说,拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源。只要CPU在发起数据传输时发送一个指令,硬件就开 始自己和内存交换数据,在传输完成之后硬件会触发一个中断来通知操作完成。这些无须消耗CPU时间的I/O操作正是异步操作的硬件基础。所以即使在DOS 这样的单进程(而且无线程概念)系统中也同样可以发起异步的DMA操作。

  线程的本质

  线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度。

  异步操作的优缺点

  因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,而且难以调试。

  多线程的优缺点

  多线程的优点很明显,线程中的处理程序依然是顺序执行,符合普通人的思维习惯,所以编程简单。但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现。

  适用范围

  在了解了线程与异步操作各自的优缺点之后,我们可以来探讨一下线程和异步的合理用途。我认为:当需要执行I/O操作时,使用异步操作比使用线程+同步 I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.net Remoting等跨进程的调用。

  而线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。但是往往由于使用线程编程的简单和符合习惯,所以很多朋友往往会使用线程来执行耗时较长的I/O操作。这样在只有少数几个并发操作的时候还无伤大雅,如果需要处理大量的并发操作时就不合适了。

实现异步编程有4种方法可供选择,这4种访求实际上也对应着4种异步调用的模式,分为“等待”和“回调”两大类。 

回调   当然属于“回调”类。推荐!!!!

  之前三种方法者在等待异步方法执行完毕后才能拿到执行的结果,期间主线程均处于等待状态。回调和它们最大的区别是,在调用BeginInvoke时只要提供了回调方法,那么主线程就不必要再等待异步线程工作完毕,异步线程在工作结束后会主动调用我们提供的回调方法,并在回调方法中做相应的处理。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace 异步调用实现方法汇总4{    ///     /// 异步调用方法总结:    /// 4.回调    /// 之前三种方法者在等待异步方法执行完毕后才能拿到执行的结果,期间主线程均处于等待状态。    /// 回调和它们最大的区别是,在调用BeginInvoke时只要提供了回调方法,那么主线程就不必要再等待异步线程工作完毕,    /// 异步线程在工作结束后会主动调用我们提供的回调方法,并在回调方法中做相应的处理,例如显示异步调用的结果。    ///     class Program    {        public delegate void PrintDelegate(string s);        static void Main(string[] args)        {            PrintDelegate printDelegate = Print;            Console.WriteLine("主线程.");            printDelegate.BeginInvoke("Hello world.", PrintComeplete, printDelegate);            Console.WriteLine("主线程继续执行...");            Console.WriteLine("Press any key to continue...");            Console.ReadKey(true);        }        public static void Print(string s)        {             Console.WriteLine("当前线程:"+s);            Thread.Sleep(5000);        }        //回调方法要求        //1.返回类型为void        //2.只有一个参数IAsyncResult        public static void PrintComeplete(IAsyncResult result)        {            (result.AsyncState as PrintDelegate).EndInvoke(result);            Console.WriteLine("当前线程结束." + result.AsyncState.ToString());        }    }}

需要注意的地方,代码中都有注明了,程序运行结果如下:

 

第一种方法:BeginEnvoke EndEnvoke方法,属于“等待”类。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace 异步调用实现方法汇总{    ///     /// 异步调用方法总结:    /// 1.BeginEnvoke EndEnvoke    /// 当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕    ///     class Program    {        public delegate void PrintDelegate(string s);        static void Main(string[] args)        {            PrintDelegate printDelegate = Print;            Console.WriteLine("主线程");            IAsyncResult result= printDelegate.BeginInvoke("Hello World.", null, null);            Console.WriteLine("主线程继续执行...");            //当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕            printDelegate.EndInvoke(result);            Console.WriteLine("Press any key to continue...");            Console.ReadKey(true);        }        public static void Print(string s)        {            Console.WriteLine("异步线程开始执行:"+s);            Thread.Sleep(5000);        }    }}

需要注意的地方,代码中都有注明了,程序运行结果如下:

第二种方法:WaitOne。同样属于“等待”类。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace 异步调用实现方法汇总2{    ///     /// 异步调用方法总结:    /// 2.WaitOne    /// 可以看到,与EndInvoke类似,只是用WaitOne函数代码了EndInvoke而已。    ///     class Program    {        public delegate void PrintDelegate(string s);        static void Main(string[] args)        {            PrintDelegate printDelegate = Print;            Console.WriteLine("主线程");            IAsyncResult result = printDelegate.BeginInvoke("Hello World.", null, null);            Console.WriteLine("主线程继续执行...");            result.AsyncWaitHandle.WaitOne(-1, false);            Console.WriteLine("Press any key to continue...");            Console.ReadKey(true);        }        public static void Print(string s)        {            Console.WriteLine("异步线程开始执行:" + s);            Thread.Sleep(5000);        }    }}

需要注意的地方,代码中都有注明了,程序运行结果如下:

 第三种方法:轮询。也是属于“等待”类。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace 异步调用实现方法汇总3{    ///     /// 异步调用方法总结:    /// 3.轮询    /// 之前提到的两种方法,只能等下异步方法执行完毕,    /// 在完毕之前没有任何提示信息,整个程序就像没有响应一样,用户体验不好,    /// 可以通过检查IasyncResult类型的IsCompleted属性来检查异步调用是否完成,    /// 如果没有完成,则可以适时地显示一些提示信息    ///     class Program    {        public delegate void PrintDelegate(string s);        static void Main(string[] args)        {            PrintDelegate printDelegate = Print;            Console.WriteLine("主线程:"+Thread.CurrentThread.ManagedThreadId );            IAsyncResult result = printDelegate.BeginInvoke("Hello world.", null, null);            Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId + ",继续执行...");            while (!result.IsCompleted)            {                Console.WriteLine(".");                Thread.Sleep(500);            }            Console.WriteLine("主线程:" + Thread.CurrentThread.ManagedThreadId + "  Press any key to continue...");            Console.ReadKey(true);        }        public static void Print(string s)        {            Console.WriteLine("当前线程:" + Thread.CurrentThread.ManagedThreadId + s);            Thread.Sleep(5000);        }    }}

需要注意的地方,代码中都有注明了,程序运行结果如下:

转载于:https://www.cnblogs.com/AmilyWilly/p/5730201.html

你可能感兴趣的文章
如何提高数据迁移和复制的速度
查看>>
.9图片
查看>>
android打开各种文件Intent
查看>>
[转][C#]单例模式之懒加载
查看>>
实验吧之【后台登录,加了料的报错注入,认真一点】(报错注入)
查看>>
MySQL无法存储Emoji表情问题
查看>>
HDFS集中式的缓存管理原理与代码剖析
查看>>
POJ1019 Number Sequence
查看>>
第十七章-异步IO
查看>>
Linux就该这么学
查看>>
out传值
查看>>
CentOS6.8【环境配置篇】
查看>>
线程同步的方式
查看>>
Mongodb 安装
查看>>
WPF窗口贴边隐藏(类似QQ)
查看>>
VS2008无法切换到视图设计器
查看>>
爱情故事:追忆似水流年 回味永恒的爱恋
查看>>
android mvn android:deploy签名问题
查看>>
transient
查看>>
[HDU 4348]To the moon
查看>>