给.neter们整理了一份《.NET/C#面试手册》,目前大约4万字左右,初衷也很简单,就是希望在面试的时候能够帮助到大家,减轻大家的负担和节省时间。对于没有跳槽打算的也可以复习一下相关知识点,就当是查缺补漏!

都是一些经典的面试题目,目前主要分为10大部分。

  • .NET/C#面试手册:基础语法
  • .NET/C#面试手册:面向对象
  • .NET/C#面试手册:集合、异常、泛型、LINQ、委托、EF!
  • .NET/C#面试手册:多线程
  • .NET/C#面试手册:ASP.NET MVC
  • .NET/C#面试手册:ASP.NET Core
  • .NET/C#面试手册:ADO.NET、XML、HTTP、AJAX、WebService
  • .NET/C#面试手册:常见的算法
  • .NET/C#面试手册:数据库概念知识
  • .NET/C#面试手册:数据库SQL查询(附建表语句)

废话不多说,本手册目前为第一版,后续慢慢也会陆续更新一些知识点,目前内容有以下板块:

《.NET/C#面试手册》包含[基础知识]、[面向对象]、[集合、异常、泛型、LINQ、委托、EF]、[ASP.NET MVC]、[ASP.NET Core]、[ADO.NET、XML、HTTP、AJAX、WebService]、[数据库知识]、[数据库SQL查询(附建表语句)]。

《.NET/C#面试手册》完整pdf、word下载地址

1.前言

异步这概念刚开始接触的时候,不是那么容易接受,但是需要用的地方还真的挺多的,刚学习的时候,也很懵逼走了不少弯路,所以这里有必要总结一下。
msdn文档:https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/
官方的简介:
*.NET Framework提供了执行异步操作的三种模式:
异步编程模型(APM)模式(也称为IAsyncResult的模式),其中异步操作要求Begin和End方法(例如,BeginWrite和EndWrite异步写入操作)。这种模式不再被推荐用于新开发。有关更多信息,请参阅异步编程模型(APM)。

基于事件的异步模式(EAP),它需要一个具有Async后缀的方法,并且还需要一个或多个事件,事件处理程序委托类型和被EventArg派生类型。EAP在.NET Framework 2.0中引入。不再推荐新的开发。有关更多信息,请参阅基于事件的异步模式(EAP)。

基于任务的异步模式(TAP),它使用单一方法来表示异步操作的启动和完成。TAP在.NET Framework 4中引入,是.NET Framework中推荐的异步编程方法。C#中的async和等待关键字,Visual Basic语言中的Async和Await运算符为TAP添加语言支持。有关更多信息,请参阅基于任务的异步模式(TAP)。*

2.异步的应用场景

在计算机程序的运行中,计算是需要一定的时间的,在运算时间过长的任务时,比如上传大文件、读取文件流、数据库操作、httprequest等,如果是同步(synvronous)必须等待该任务执行完成才能继续下一个任务。使用异步(asynchronous)操作,会开启新的线程,不会等待异步操作完成才去执行后面的程序,相比异步编程优点:1.就是出现长时间处理程序时,不会卡界面,用户仍然可以操作UI界面2.提高程序运行效率,节约CPU资源,提供系统吞吐量。

3.进程和线程的关系

这个面试的时候基本上都会问到,简而言之就是:
一个程序都会有一个进程和一个线程,进程是由CPU进行调度分配资源的,有一个完整的虚拟地址空间,不依赖线程独立存在,反之线程是由进程来调度分配的,只是进程的一部分,没有自己的地址空间,与进程内的其他线程一起共享该进程的所有资源。打个简单的比方就像是线程就好比是人体的寄生虫,不能独立存在,必须依靠人(进程)的营养(资源)来生存(执行)

4.异步和多线程的区别

异步是相对同步而言的,我们知道异步是开启了新线程,但是和多线程不是一个概念,异步相当于一个人的“大脑”能够做试卷,又能够看电影,同时处理两件以上不同的事情。多线程好比多个人做不同的事情。
异步操作的本质
c#中异步和多线程的区别是什么呢?异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性。 所有的程序最终都会由计算机硬件来执行,无须消耗CPU时间的I/O操作正是异步操作的硬件基础。
线程的本质
线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是进程中一段并发运行的代码,所以线程需要操作系统投入CPU资源来运行和调度
异步操作的优缺点
因为异步操作无须额外的线程负担,并且使用回调的方式进行处理,在设计良好的情况下,处理函数可以不必使用共享变量(即使无法完全不用,最起码可以减少 共享变量的数量),减少了死锁的可能。当然异步操作也并非完美无暇。编写异步操作的复杂程度较高,程序主要使用回调方式进行处理,与普通人的思维方式有些出入,而且难以调试。
多线程的优缺点
  多线程的优点很明显,线程中的处理程序依然是顺序执行,符合普通人的思维习惯,所以编程简单。但是多线程的缺点也同样明显,线程的使用(滥用)会给系统带来上下文切换的额外负担。并且线程间的共享变量可能造成死锁的出现。
适用范围
当需要执行I/O操作时,使用异步操作比使用线程+同步 I/O操作更合适。I/O操作不仅包括了直接的文件、网络的读写,还包括数据库操作、Web Service、HttpRequest以及.net Remoting等跨进程的调用。
而线程的适用范围则是那种需要长时间CPU运算的场合,例如耗时较长的图形处理和算法执行。但是往往由于使用线程编程的简单和符合习惯,所以很多朋友往往会使用线程来执行耗时较长的I/O操作。这样在只有少数几个并发操作的时候还无伤大雅,如果需要处理大量的并发操作时就不合适了。
参考:http://www.cnblogs.com/DebugLZQ/archive/2012/09/05/2670986.html

5.C#异步方式之一( BeginInvoke、EndInvoke方法)

方式1:使用回调方法完成异步委托
先来看个例子,委托的异步调用,这个例子首先定义一个string类型的返回值、string类型的参数的委托。虽然这中模式不推荐被使用。

    class Program{delegate string SayHi(string name);//定义委托static void Main(string[] args){SayHi sayhi = new SayHi(SayHiName);//实例化委托sayhi("科比");//一般的直接调用sayhi.Invoke("张林");//使用Invoke方法同步调用//异步调用sayhi.BeginInvoke("杜兰特", (IAsyncResult ar) =>{sayhi.EndInvoke(ar);Console.WriteLine("打招呼成功结束"); }, null);}public static string SayHiName(string  name){return "how are you"+name + "?";}}

前两种调用委托的方式都是同步的,BeginInvoke方法的返回值是IAsyncResult类型的
该方法的参数由两部分组成,前面(n)个参数是委托的参数,倒数第二个参数也表示一个委托,该委托是.net系统定义的委托(和func、action类似),查看AsyncCallback的定义如图:

作用就是:作为执行调用的回调方法,值得注意的是,在回调方法中,必须调用EndInvoke方法结束异步调用,EndInvoke是获取异步调用的结果
上面的例子调试的结果如图:

方式2:使用轮询
我们把BeginInvoke的委托参数为null,使用轮询的方式

   Func<string, string> func = delegate (string name){Thread.Sleep(2000);return "how are you" + name + "";};IAsyncResult ar = func.BeginInvoke("张林",null,null);int i = 1;while (!ar.IsCompleted){Console.WriteLine(200*i);i++;Thread.Sleep(200);}string result = func.EndInvoke(ar);Console.WriteLine(result);

结果如图:

6.C#异步方式之二 await async

async和await是一对关键字,它是.net 4.5的特性。在实际工作中使用方便灵活,主要原因就是可以像写同步方法那样去异步编程,代码结构清晰,不用关心如何实现异步的编程。
这里其实要注意的是,之前刚说了异步是开启新的线程来实现的,但是await 和async两个关键字并没有开启新的线程,为了证明这一点,下面建了一个winform的程序,异步获取图片并显示到picturebox上。

   public Form1(){InitializeComponent();this.label1.Text = "主线程Id:"+Thread.CurrentThread.ManagedThreadId;}private  async void button1_Click(object sender, EventArgs e){string imageUrl = "https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=3850265187,1181041963&fm=173&s=62E19A4722716A371EB097FB03009015&w=218&h=146&img.JPEG";HttpClient client = new HttpClient();var response =await  client.GetAsync(imageUrl);if (response.StatusCode == System.Net.HttpStatusCode.OK){var stream =await response.Content.ReadAsStreamAsync();Image  image = Bitmap.FromStream(stream,true);this.label2.Text = "线程Id:" + Thread.CurrentThread.ManagedThreadId;this.pictureBox1.BackgroundImage = image;}}

其实不用看图就已经知道答案了,程序运行时不报异常,就已经说明一点:await async两个关键根本创建新的线程。这个涉及到异步更新UI到主线程,就不多说了。
结果如图:


async await方法的使用说明:

  • 返回类型: void 、Task、Task<泛型类型>
  • async、await不会创建新的线程,实现等待的效果,必须同时使用
  • 使用该方法的方法主体也要用async关键字

异步方法事例:

     private static async Task<int> GetValueAsync(int a){//Task.run 开启了新的线程await  Task.Run(() =>{Thread.Sleep(2000); //模拟耗时Console.WriteLine("GetValueAsync方法结束,线程ID:" + Thread.CurrentThread.ManagedThreadId);return a * a;});Console.WriteLine("线程ID:" + Thread.CurrentThread.ManagedThreadId+"异步方法结束");return a * a;}

调用异步方法:

  private async void button1_Click(object sender, EventArgs e){int result =await GetValueAsync(5);this.label1.Text = "异步计算的结果" + result + "线程ID:" + Thread.CurrentThread.ManagedThreadId;}

7.C#异步方式之三 浅谈Task

前面刚刚了解到async await是.net 4.5出的特性,Task是.net4.0新出的特性,用来处理异步编程的,其实我们要知道真正实现的异步操作还是Task新增线程来实现的,但是不代表说开一个Task,就开一个线程,有可能是几个Task在一个线程上运行的,他们并不是一一对应的关系,充分利用线程,下面的事例就已经能够说明这一点
Task创建
Task创建有两种方式一种通过任务工厂赋值立即运行,一种是直接实例化。下面这个例子创建了10个Task

     static  void Main(string[] args){//启用线程池中的线程异步执行Task t1 = Task.Factory.StartNew(() =>{Console.WriteLine("Task1启动...线程ID:"+Thread.CurrentThread.ManagedThreadId);});Task t2 = Task.Factory.StartNew(() =>{Console.WriteLine("Task2启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});//new 实例化启动Task t3 = new Task(() =>{Console.WriteLine("Task3启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});t3.Start();Task t4 = Task.Factory.StartNew(() =>{Console.WriteLine("Task4启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t5 = Task.Factory.StartNew(() =>{Console.WriteLine("Task5启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t6 = Task.Factory.StartNew(() =>{Console.WriteLine("Task6启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t7 = Task.Factory.StartNew(() =>{Console.WriteLine("Task7启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t8 = Task.Factory.StartNew(() =>{Console.WriteLine("Task8启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t9 = Task.Factory.StartNew(() =>{Console.WriteLine("Task9启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Task t10 = Task.Factory.StartNew(() =>{Console.WriteLine("Task10启动...线程ID:" + Thread.CurrentThread.ManagedThreadId);});Console.ReadLine();}

创建的10个Task,我们从结果中也证明了Task和线程并不是一一对应的关系,结果如图:

Task构造函数

Task状态
我们创建一个task,调用他的Start、Wait方法

 static  void Main(string[] args){var task = new Task(()=> {Console.WriteLine("Task创建成功");});Console.WriteLine("task未开始:"+task.Status);task.Start();Console.WriteLine("task已经开始:"+task.Status);task.Wait();Console.WriteLine("task已经等待:"+task.Status);}

结果如图:

我们从图中可以知道,Task的生命周期如下:
Created:在已经实例化未Start之前的状态
WaittingToRun:表示等待分配线程给Task执行
RanToCompletion:任务执行完毕

Task等待任务结果
1.Task.WaitAll从这个字面意思就知道等待所有任务执行完成,和上面例子Wait方法等待一个任务执行完成很相似,我们来看一个代码:

 var task1 = new Task(() =>{System.Threading.Thread.Sleep(3000);Console.WriteLine("task1Created");});var task2 = new Task(() =>{System.Threading.Thread.Sleep(3000);Console.WriteLine("task2Created");});task1.Start();task2.Start();Task.WaitAll(task1, task2);Console.WriteLine("所有任务执行完!");Console.Read();

结果输出:
task1Created
task2Created
所有任务执行完
除了WaitAll方法还有这些常用的方法

  • Task.WaitAny:等待任何一个任务向下执行
  • Task.ContinueWith等待第一个Task完成自动启动,触发下一个Task,也就是当做任务完成时触发的回调方法
  • Task.GetAwaiter().OnCompleted(Action action) :GetAwaiter 方法获取任务的等待者,调用OnCompleted事件,任务完成时触发

Task任务取消

   static  void Main(string[] args){var source = new CancellationTokenSource();var token = source.Token;Task t1 = Task.Run(() =>{Thread.Sleep(2000);if (token.IsCancellationRequested){Console.WriteLine("任务已取消");}Thread.Sleep(1000);},token);Console.WriteLine(t1.Status);//取消任务source.Cancel();Console.WriteLine(t1.Status);Console.ReadLine();}

结果如图:

总结:
纸上得来终觉浅,绝知此事要躬行。很多实际的异步问题还是需要在实践中去体会,实践是检验真理的唯一标准。

作者信息
【文章信息】:作者-张林:原文链接-https://blog.csdn.net/kebi007/article/details/76899078
【原创公众号】:dotNet全栈开发。好文目录
版权声明:本文为CSDN博主「dotNet全栈开发」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

C#异步编程基础入门总结相关推荐

  1. [NodeJS]Node异步编程基础

    零.前言 为什么要用Node? Node把非阻塞IO作为提高应用性能的方式.而在JS中,天生拥有着异步编程机制: 事件机制.同时JS中不存在多进程.这样当你执行相对较慢需要花费时间长的IO操作时并不会 ...

  2. python快乐编程—基础入门-从萌新到大神必读书籍 《Python快乐编程基础入门》...

    2019年,全球信息化进程持续加快,IT行业繁荣发展.作为新时代IT人,不仅需要强大的理论知识,更需要过硬的技术.Python作为最受欢迎的编程语言之一,作为人工智能时代的首选语言,因其受众多.用途广 ...

  3. java socket 异步回调函数,分享nodejs异步编程基础之回调函数用法

    nodejs异步编程基础之回调函数用法分析 本文实例讲述了nodejs异步编程基础之回调函数用法.分享给大家供大家参考,具体如下: Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实 ...

  4. WPF编程基础入门 ——— 第二章 XAML

    XAML 简述 XAML(eXtensible Application Markup Language,可扩展应用程序标记语言)是微软公司创建的一种新的描述性语言,用于搭建应用程序用户界面.XAML实 ...

  5. 「Linux」Linux Shell 编程基础入门

    Linux Shell 编程基础入门 1. 变量 1.1 变量定义 1.2 使用变量 1.3 引号 1.4 将命令的结果赋值给变量 1.5 位置参数 1.6 特殊变量及其含义 2. 字符串 2.1 字 ...

  6. WPF编程基础入门 ——— 第三章 布局(五)布局面板WrapPanel

    WPF布局--布局面板WrapPanel WPF--WrapPanel布局控件 WrapPanel实例--十个按钮 WPF--WrapPanel布局控件 WrapPanel(自动折行面板),允许任意多 ...

  7. Delphi多线程编程基础入门

    1. 概述 对于开发人员来说,多线程是必备的知识,但相对来说,也是比较难的知识点.Delphi是一门古老而优秀的编程语言,它对多线程的处理有一些特殊的地方,本文尝试做一些简单的讲解,可以当作Delph ...

  8. Python异步编程实战入门:从概念到实战

    概述 读者可前往我的博客获得更好的阅读体验 在Python中存在GIL机制,该机制保证了在Python中同时间内仅能运行一行代码,这导致了Python无法真正实现多线程,但可以通过多进程打破GIL限制 ...

  9. 一文了解异步编程基础

    什么是异步编程? 异步编程是指并发编程的范式,其中除了单个主应用程序线程之外,工作可以委托给一个或多个并行工作线程.这被称为非阻塞系统,其中整体系统速度不受订单执行的影响,并且多个进程可以同时发生. ...

最新文章

  1. c语言进制转换pdf下载,C语言实现任意进制转换.doc
  2. HashMap 源码深入浅出
  3. CF1097D Makoto and a Blackboard(期望)
  4. 单网段DHCP服务器的架设
  5. MongoDB的简单操作
  6. java 内存泄漏 工具_Java剖析工具JProfiler入门使用教程:查找内存泄漏的方法
  7. 【DevOps+LIVE】直播复盘 – DevOps能力成长模型2018首发
  8. block在美团iOS的实践
  9. 无限级导航PHP,jQuery多级无限级导航下拉菜单代码
  10. 【java学习之路】(javaWeb【后端】篇)006.FilterListener
  11. 求一个容器的最值的索引_初中几何最值——瓜豆原理模型分析
  12. Verilog语法入门
  13. yii2中hasMany 和 hasOne 的用法及在页面中增加字段的问题
  14. win10右键一直转圈_win10 系统 桌面点右键经常转圈圈卡住。
  15. Java SSL实现使用详解
  16. COOKIE与SESSION比较
  17. 第四章课后习题-用Python实现羊车门问题,最大公约数计算,猜字游戏,统计不同字符个数。
  18. ubuntu项目移植windows
  19. JVM00_面试官对类加载器子系统、运行时数据区、内存分布、执行引擎的灵虚拷问,你能坚持到第几问?
  20. Super Jumper:一个2DOpenGL ES游戏

热门文章

  1. 使用云服务器搭建个人简历网页
  2. .babelrc详解
  3. 2020.9月做题记录
  4. Ubuntu16.04保存/home盘下的数据重装Ubuntu系统
  5. 在win8上构建按拼音排序的GridView控件
  6. js 如何代替java中的长整型_Javascript长整型
  7. 2022081班李亚楠20220927
  8. 腾讯元老赚够钱后辞职到安徽农村隐居,亲手建造200亩农场
  9. 睿智的目标检测23——Pytorch搭建SSD目标检测平台
  10. Nokia E52 使用技巧