1 异步编程的重要性

  C#5.0最重要的改进是提供了更强大的异步编程,C#5.0仅增加两个关键字Async和Await,使用异步编程,方法调用是后台运行(通常在线程和任务的帮助下),并且不会阻塞调用线程。

2 异步模式

  从.net1.0开始就提供了异步特性,而且.NET Framework的许多类都实现了一个或多个异步模式(委托也实现了异步模式)。因为在WIndows From和WPF中用异步模式更新界面比较复杂,所以在2.0中提供了基于事件的异步模式。现在在4.5中推出了另外一种新的方式来实现异步编程:基于任务的异步模式。这种模式是基于4.0中新增的Task类型,和一个利用Async和Await关键字的编译器功能。

2.1 同步调用

WebClient wc = string s= wc.DownloadString("你的URL");

  运行该代码,程序一直在等待DownloadString的完成,在这种情况下使用异步非常有必要的。

2.2异步模式

使用异步模式是进行异步调用的方式之一,实现异步模式定义BeginXXX和EndXXX方法。如果有一个同步方法DownloadStrring,异步方法将转化成了两个方法BeginDownloadString和EndDownloadString方法。BeginXXX方法接受同步方法的所有输入的参数,并且还定义了一个AsyncCallBack参数,用于接收在异步方法执行完毕后的被调用的委托,该方法返回一个IAsyncResult,用于验证调用是否已经完成,并且一直等待,直到方法的执行完毕。EndXXX方法同步方法的所有的输出参数,并按照同步方法的返回类型来返回结果。WebClient类没有实现异步模式,但可以用HttpWebRequest来代替

  HttpWebRequest req =(HttpWebRequest)WebRequest.Create("你的URL");
             IAsyncResult result=  req.BeginGetResponse("",);
             req.EndGetResponse();

异步模式的优势是使用委托功能就能实现异步编程,不用改变程序的行为,也不会阻塞界面的操作。

2.3基于事件的异步模式

  基于事件的异步模式定义了一个带有"Aysnc"后缀的方法。异步方法完成时不是定义被调用的委托,而是定义事件。

 WebClient client = new WebClient();
             client.DownloadStringCompleted += (sender, e1) => { };
             client.DownloadStringAsync(new Uri("你的URL"));

基于事件的异步方式的优势是易用。

2.4基于任务的异步模式

 public async void Fun()
         {
             WebClient client = new WebClient();
             string s = await client.DownloadStringTaskAsync("你的URL");
         }

现在代码简单多了,并且没有阻塞。

3 异步编程的基础

  async和await关键字只是编译器功能,编译器会用Task创建代码。

3.1创建任务

         static string Greeting(string name)
         {
             Thread.Sleep();
             return string.Format("Hello ,{0}", name);
         }
         static Task<string> GreetingAsync()
         {
             return Task.Run<string>(()=> { return Greeting(name); });
         }

3.2调用异步方法

  可以使用Await关键字来调用返回任务的异步方法GreetingAsync,使用Await关键字需要使用Async修饰声明的方法。在完成GreetingAsync方法前该方法内的其它代码不会被执行。

   private async static void CallWithAsync()
         {
             string result = await GreetingAsync("郑隆");
             Console.WriteLine(result);
         }

如果异步方法的结果不传递给变量,也可以直接在参数中使用Await关键字。

  private async static void CallWithAsync2()
         {
             Console.WriteLine(await GreetingAsync("郑隆"));
         }
Async修饰符只能用于返回Task和void的方法。不能用于程序的入口。

3.3延续任务

Task类的ContinueWith方法定义了任务完成后将要调用的代码。

    private static void CallerWithContinuationTask()
         {
             Task<string> t1 = GreetingAsync("郑隆");
             t1.ContinueWith(t => { string result = t.Result; Console.WriteLine(result); });
         }

3.4使用多个异步方法

在一个异步方法中,可以调用不止一个异步方法。

  public async static void MultipleAsyncMethods()
         {
             string s1 = await GreetingAsync("zhenglong1");
             string s2 = await GreetingAsync("zhenglong2");
             Console.WriteLine("Finished both methods.\n"+"Result 1:{0}\n Result 2:{1}",s1,s2);
         }

Task.WhenAll组合器,可以让你等待直到两个任务都完成。

  public async static void MultipleAsyncMethodsWithCombinators1()
         {
             Task<string>  t1= GreetingAsync("zhenglong1");
             Task<string> t2 = GreetingAsync("zhenglong2");
             await Task.WhenAll(t1,t2);
             Console.WriteLine("Finished both methods.\n" + "Result 1:{0}\n Result 2:{1}", t1.Result, t2.Result);
         }

Task的WhenAll方法是在所有传入的任务都完成了才返回Task,而WhenAny是在其中的一个任务已完成就会返回Task。

3.5转换异步模式

并非.NET Freamwork的所有的类在4.5中都引入了新的异步方法。

 private static Func<string, string> greetingInvoker = Greeting;

         static IAsyncResult BeginGreeting(string name,AsyncCallback callback,object state)
         {
             return greetingInvoker.BeginInvoke(name, callback, state);
         }
         static string EndGreeting(IAsyncResult ar)
         {
            return greetingInvoker.EndInvoke(ar);
         }
  private async static void ConvertingAsyncPattern()
         {
             string s = await Task<string>.Factory.FromAsync(BeginGreeting, EndGreeting, "zhenglong", null);
             Console.WriteLine(s);
         }

4 错误处理

   public static async Task ThrowAfter(int ms,string message)
         {
             await Task.Delay(ms);
             throw new Exception(message);
         }

         public static void DontHandle()
         {
             try
             {
                 ThrowAfter(,"first");
             }
             catch (Exception ex)
             {
              }
         }

以上代码并不能捕获到异常,应为在ThrowAfter抛出异常之前DontHandle已经执行完了。

4.1 异步方法的异常处理

异步方法异常的一个较好的处理是使用关键字Await,然后将其放在try中

    public async static void HandleErrorOne()
         {
             try
             {
                 , "first");
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }

4.2 多个异步方法的异常处理

   public static async void StatTwoTasks()
         {
             try
             {
                 ,"frist");
                 , "second");
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }

如上代码并不能捕获全部的异常,原因是因为在第一个异常抛出后程序就进入了catch。解决方法

  public static async void StatTwoTasksParallel()
         {
             try
             {
                 Task t1 = ThrowAfter(, "zhenglong1");
                 Task t2 = ThrowAfter(, "zhenglong2");
                 await Task.WhenAll(t1,t2);
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }

4.3 AggregateException类

为了得到所有的异常信息,可以将Task.WhenAll返回的结果写到一个Task中,这个任务一直等待所有的任务完成。

 public static async void ShowAggregateException()
         {
             Task taskResult = null;
             try
             {
                 Task t1 = ThrowAfter(, "zhenglong1");
                 Task t2 = ThrowAfter(, "zhenglong2");
                 await(taskResult= Task.WhenAll(t1, t2));
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
                 foreach (var item in taskResult.Exception.InnerExceptions)
                 {
                     Console.WriteLine(item.Message);
                 }
             }
         }

5取消

在某种情况下,后台任务可能运行很长的时间,取消任务就非常有用了。

5.1 开始取消任务

 private CancellationTokenSource cts;
         public void Cancle()
         {
             if (cts != null)
                 cts.Cancel();
         }
CancellationTokenSource 类还支持在指定时间后才取消任务,CancelAfter方法在应该取消的任务后传入一个时间值,单位是ms.

5.2开始框架的特性任务取消

  public async void CancelTwo()
         {
             cts = new CancellationTokenSource();
             HttpClient hc = new HttpClient();
             var s=await hc.GetAsync("Url", cts.Token);
         }

5.3取消自定义任务

  await Task.Run(()=> { },cts.Token);

现在用户就可以取消运行时间长的任务了。

C#之异步编程的更多相关文章

  1. C#异步编程(一)

    异步编程简介 前言 本人学习.Net两年有余,是第一次写博客,虽然写的很认真,当毕竟是第一次,肯定会有很多不足之处, 希望大家照顾照顾新人,有错误之处可以指出来,我会虚心接受的. 何谓异步 与同步相对 ...

  2. C#与C++的发展历程第三 - C#5.0异步编程巅峰

    系列文章目录 1. C#与C++的发展历程第一 - 由C#3.0起 2. C#与C++的发展历程第二 - C#4.0再接再厉 3. C#与C++的发展历程第三 - C#5.0异步编程的巅峰 C#5.0 ...

  3. 关于如何提高Web服务端并发效率的异步编程技术

    最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...

  4. 异步编程 In .NET

    概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们 ...

  5. C#异步编程(二)

    async和await结构 序 前篇博客异步编程系列(一) 已经介绍了何谓异步编程,这篇主要介绍怎么实现异步编程,主要通过C#5.0引入的async/await来实现. BeginInvoke和End ...

  6. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  7. [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程

    怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html  ...

  8. [C#] 走进异步编程的世界 - 开始接触 async/await

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  9. C#异步编程

    什么是异步编程 什么是异步编程呢?举个简单的例子: using System.Net.Http; using System.Threading.Tasks; using static System.C ...

  10. 深入解析js异步编程利器Generator

    我们在编写Nodejs程序时,经常会用到回调函数,在一个操作执行完成之后对返回的数据进行处理,我简单的理解它为异步编程. 如果操作很多,那么回调的嵌套就会必不可少,那么如果操作非常多,那么回调的嵌套就 ...

随机推荐

  1. 14.1.1 InnoDB as the Default MySQL Storage Engine

    14.1 Introduction to InnoDB 14.1.1 InnoDB as the Default MySQL Storage Engine 14.1.2 Checking InnoDB ...

  2. 请问,如何在windows系统下面同时使用中文和英文的cmd?_百度知道

    请问,如何在windows系统下面同时使用中文和英文的cmd?_百度知道 在批处理开始加一行chcp 437就是英文的cmdchcp 936就是中文的cmd

  3. C++建立动态二维数组

    C++建立动态二维数组主要有两种方法: 1.使用数组指针,分配一个指针数组,将其首地址保存在b中,然后再为指针数组的每个元素分配一个数组                           int * ...

  4. Linux系统基础命令

    这是看itercast的学习笔记 Linux系统基础命令 日期时间 命令date用以查看.设置当前系统时间:格式化显示时间: +%Y--%m--%d 命令hwclock(clock)用以显示硬件时钟时 ...

  5. iOS基本控制-UINavigationController 传统的价值观,代理传统价值观,正向传统价值观,反传统的价值观

    /*        程序过程:  1.创建一个根视图,一个二级视图  2,根视图NavigationItem.title = Root 二级视图NavigationItem.title = Secon ...

  6. centos 安装ganglia监控工具

    一个.ganglia基本介绍 ganglia它是一个分布式监控系统,那里有两个Daemon,每间:clientGangliaMonitoring Daemon (gmond)和服务端GangliaMe ...

  7. CImageList使用简要说明

    CImageList ImageList;//创建一个包含3个24位色32x32图片的ImageList,ILC_MASK的意思是同时创建一个mask,这样在下面指定了背景颜色以后ImageList就 ...

  8. Android编程心得-Handler与子线程的交互初步

    在编写项目的时候,本人发现一个关于线程与Handler很容易犯的错误. 我有两个Activity,一个Activity在后台创建了一个线程并且启动,这个线程对象对应的实体实在另外一个Activity的 ...

  9. 马航MH17事件将把普京逼入绝境?

    据7月22日报道,马克兰东部民间武装22日凌晨将失事客机的"黑匣子"交给马来西亚方面.乌政府与民间武装允许在坠机地点附的小范围停火. 与此同一时候,联合国安理会21日通过决议,敦促 ...

  10. IDL 自己定义功能

    function add,x,y return, x+y end pro sum x=1 y=2 print,add(x,y) end 版权声明:本文博客原创文章,博客,未经同意,不得转载.