【C#】49. async, await 基础

9 篇文章 2 订阅
5 篇文章 0 订阅

这篇文章主要介绍一下C# 5.0语法中的新组合:async 和 await。我这里主要会写一些基本的注意要点,但是不会过于仔细。

首先,必须要说明的是async和await是一对,要使用await关键字,那么函数前必须要有async前缀;这对语法糖不能使用在catch、finally、lock、unsafe代码中;且函数参数不能有out或者ref修饰;异步函数必须返回Task或者Task<T>类型

比较典型的使用情况是使用await Task.Delay(2000),来让线程等待2秒钟(但是不同于Thread.Sleep(2000),后者会阻塞线程,而前者会释放线程回到线程池中,进而节省线程资源)。

async static Task<string> GetInfoAsync(string name)
{
await Task.Delay(2000);
return string.Format("Task {0} 运行在线程Id为 {1}的线程上。是否是线程池线程: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}

GetInfoAsync函数使用了前缀async,主要是为了使得函数体内可以使用await Task.Delay()。当然,你也可以使用像上篇中讲到的用:

Task delay = Task.Dealy(2000); 
Return delay.ContinueWith(t=>return  string.Format("Task {0} 运行在线程Id为 {1}的线程上。是否是线程池线程: {2}",name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); );

可以明显的感受到,前者的代码量少了一些,而且逻辑也更加简单。但是,作为一个新手,我还是觉得使用了Async后,本应该返回一个Task<String>的,现在返回了一个String,这个有点奇怪。我就简单地理解为只要有async作为Task<T>的前缀,那么就要返回T类型数据;如果是async作为Task的前缀,那么不用返回同样,如果要得到返回的T类型结果,那么在调用该函数时必须加前缀await;反之,则只是返回一个Task<T>。这里如果有不对还请大师们指点。




一、首先来看传统的Task TPL方法:

static Task AsynchronyWithTPL()
{
Task<string> t = GetInfoAsync("Task 1");
Task t2 = t.ContinueWith(task => Console.WriteLine(t.Result), TaskContinuationOptions.NotOnFaulted);
Task t3 = t.ContinueWith(task => Console.WriteLine(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
return Task.WhenAny(t2, t3);
}

调用函数:

Task t = AsynchronyWithTPL();
t.Wait();

简单说明一下,主线程中调用的Wait()是能够自动启动相关的Task的。AsynchronyWithTPL中里面用了Task.WhenAny()方法来返回一个Task。注意下t2和t3的状态条件!





二、再来看一下Await的使用


async static Task AsynchronyWithAwait()
{
try
{
string result = await GetInfoAsync("Task 2"); //有了await则返回String类型。
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}


这里加了try catch是为了之后做Throw Exception做准备的。


三、await异常捕获


async static Task<string> GetInfoAsync(string name)
{
await Task.Delay(2000);
throw new Exception("Boom!");
return string.Format("Task {0} 运行在线程Id为 {1}的线程上。是否是线程池线程: {2}",
name, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}

不同于以往我们说的,不同线程是无法处理其他线程抛出的异常。这里我们在
AsynchronyWithAwait
函数中直接使用了我们通常熟悉的Try Catch方式,主线程(AsynchronyWithAwait 其实运行在主线程上)正确的捕获了由线程池线程引发的异常。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值