多线程编程学习笔记——async和await(一)
通过前面的文章,已经学习了怎么使用线程,怎么使用线程同步,怎么使用线程池,怎么使用任务并行库。尽管通过上面的学习,对于线程的使用越来越简单。有没有更简单的方法呢。
C# 5.0之后,微软在c#语言中添加了两个关键字async与await,这是在TPL上面的更高一级的抽象,真正简化了异步编程的编程方式,从而有助于我们编写出真正健壮少bug的异步应用程序。下面我先来看一个最简单的示例。
async Task<string> AsyncHello()
{ await Task.Delay(TimeSpan.FromSeconds());
Return “ Hello world”;
}
使用async标记异步函数,建议返回async Task<T>。
Await只能使用在有async标志的方法内部。在async标记的方法内部最少要有一个await,当然,如果一个也没有,编译也不会报错,但是会有编译警告。如下图。
上面的代码在执行完await调用的代码之行后该方法会直接返回。如果同步执行,执行线程会阻塞2秒之后返回结果,本示例里在执行完await操作后,立即将工作线程放回线程池中,我们会异步等待。2秒后,我们会从线程池中取得工作线程并继续运行其中剩余的异步方法。这就允许我们在等待的2秒的时间里可以重用线程池中的线程,这对提高应用程序的可伸缩性非常重要。通过使用async与await我们拥有了线性的程序控制流程,但是执行过程却是异步的。
一、 使用await获取异步操作结果
本示例是学习await如何获取异步操作结果。同时会与TPL进行比较。
1.示例代码如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace ThreadAsyncDemo
{ class Program
{
static void Main(string[] args)
{ Task t = AsyncWithTPL();
t.Wait();
t = AsyncWithAwait();
t.Wait();
Console.Read();
} static Task AsyncWithTPL()
{
Task<string> task1 = GetInfoAsync("Task 1"); Task task2 = task1.ContinueWith(task =>
Console.WriteLine(task1.Result), TaskContinuationOptions.NotOnFaulted);
Task task3 = task1.ContinueWith(task =>
Console.WriteLine(task1.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);
return Task.WhenAny(task2, task1); } async static Task AsyncWithAwait()
{
try
{
string result = await GetInfoAsync("Task 4");
Console.WriteLine(result);
} catch (Exception ex)
{
Console.WriteLine(ex.Message); }
} async static Task<string> GetInfoAsync(string name)
{ await Task.Delay(TimeSpan.FromSeconds());
//throw new Exception("抛出异常信息!"); return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工作线程是否是线程池中的线程:{2}", name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); }
}
}
2.程序运行的结果如下图。
程序同时运行了两个异步操作。其中一个是标准的TPL代码,另一个使用了async与await两个关键字。AsyncWithTPL启动了一个任务,运行两秒之后返回关于工作线程信息的字符串。然后我们定义了一个后续操作,用于在异步操作完成后打印出操作结果,还有另一个后续操作,用于万一有错误时,打印出异常信息。最终返回了一个代表其中一个后续操作任务的任务,并等等其在主函数中完成。
在asyncWithAwait方法中,我们对任务使用await并得到了相同 的结果。这和编写普通的同步代码的风格一样,即我们获取了任务的结果,打印了出来,如果任务完成时带有错误则捕获异常。关键不同的是这实际上是一个异步操作。使用await后,c#立即创建了一个任务,其中一个有后续操作任务,包含了await操作符后面的所有剩余代码。这个新任务也处理了异常。然后这个任务返回 到主方法并等待共完成 。
因此可以看出程序中的两段代码在概念上是相同的,使用await由编译 器隐式地处理了异步代码。
3. 我们把上面注释的抛出异常的代码,取消注释,然后运行程序。得到如下图的结果。
注:在gui与asp.net之类的环境 中不推荐 使用task.wait和taskResult方法同,因为如果代码写的不好,很容易导致死锁。
二、 在Lambda表达式中使用await操作符
本示例学习如何在lambda表达式中使用await。将学习如何编写一个使用了await的匿名方法,并且获取异步执行该方法的结果。
1.示例代码如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading; namespace ThreadAsyncDemo
{ class Program
{ static void Main(string[] args)
{ Task t = AsyncProcess();
t.Wait();
Console.Read();
} async static Task AsyncProcess()
{ Func<String, Task<string>> asyncLambda = async name =>
{ await Task.Delay(TimeSpan.FromSeconds());
return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工作线程是线程池的线程:{2}" ,name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}; string result = await asyncLambda("async lambda");
Console.WriteLine(result); } } }
2.程序运行结果,如下图。
首先不能在main方法中使用async,我们将异步函数移到了asyncProcess中,然后使用async关键字声明了一个lambda表达式。由于 任何lambda表达式的类型都不能通过lambda自身来推断,所以不得不显示地指定类型为一字符串,并返回一个Task<string>对象 。
然后,我们定义 了lambda表达式体,这个方法虽然定义返回的是一个Task<string>对象 ,但实际上返回的是字符串,却没有编译错误。这是因为c#编译器自动 产生了一个任务并返回给我们。
最后一步就是打印出lambda 表达式执行后的结果。
多线程编程学习笔记——async和await(一)的更多相关文章
- 多线程编程学习笔记——async和await(二)
接上文 多线程编程学习笔记——async和await(一) 三. 对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...
- 多线程编程学习笔记——async和await(三)
接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五. 处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...
- 多线程编程学习笔记——使用异步IO(一)
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端
接上文 多线程编程学习笔记——使用异步IO 二. 编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...
- 多线程编程学习笔记——异步调用WCF服务
接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...
- 多线程编程学习笔记——使用异步IO
接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...
- [Java123] JDBC and Multi-Threading 多线程编程学习笔记
项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5 :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...
- Java多线程编程(学习笔记)
一.说明 周末抽空重新学习了下多线程,为了方便以后查阅,写下学习笔记. 有效利用多线程的关键是理解程序是并发执行而不是串行执行的.例如:程序中有两个子系统需要并发执行,这时候需要利用多线程编程. 通过 ...
- python学习笔记 async and await
用asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from调用另一个coroutine实现异 ...
随机推荐
- 用js判断是否为手机浏览,如果是手机浏览就跳转到手机站
<script type="text/javascript"> function browserRedirect() { var sUserAgent= navigat ...
- Java反射机制能够获取的信息,与应用
一.什么是Java反射机制? [1]反射机制是在运行状态中,对于任何一个类,都能够知道这个类的所有属性和方法: [2]对于任意一个对象,都能够调用它的任意一个属性和方法: 像这种动态获取类的信息以及动 ...
- .Net Core在Ubuntu上操作MySql折腾实录
.Net Core 2.0 发布也这么久了,一直想着折腾着玩玩,无奈一直没时间,这几天准备开始好好学习下C#在跨平台方面的应用,记录下来以备自己以后回忆.学习. 本篇博客的主要内容: MySql在Ub ...
- 一个基于EntityFramework Core的简单数据库访问层,适用于轻量级数据库业务
这个访问层的代码实际上是园子里某个前辈的,本人只是觉得好使,记录了下来. 本访问层需要通过Nuget安装EntityFramework Core,不过个人认为EF 6同样可以使用. 搭配数据库,最好是 ...
- Hadoop,master和slave简单的分布式搭建
搭建过程中配置免密钥登录为了以后方便使用 [提醒]安装Hadoop中会遇到新建文件夹,配置路径等问题,这个不能生搬硬套,要使用自己配置的路径,灵活使用. Hadoop的部署配置文件在http://bl ...
- C#设计模式之十二享元模式(Flyweight)【结构型】
一.引言 今天我们要讲[结构型]设计模式的第六个模式,该模式是[享元模式],英文名称是:Flyweight Pattern.还是老套路,先从名字上来看看."享元"是不是可以这样 ...
- ionic3.0--angular4.0 引入第三方插件库的方法
ionic3.0 引入第三方插件 (swiper),方法很多,现详细说明下官方推荐(typings)做法. 1.全局安装Typings 1. npm install -g typings 2.搜索你 ...
- Ubuntu16 远程连接MySQL
1.进入MySQL配置目录允许其他IP可以链接 vi /etc/mysql/mysql.conf.d/mysqld.cnf 吧下面这行注释掉 #bind-address = 127.0.0.1 2.远 ...
- JavaScript系列----事件机制
1.事件流 1.1.标准事件流 所谓的标准事件流指的的:EMCAScript标准规定事件流包含三个阶段,分别为事件捕获阶段,处于目标阶段,事件冒泡阶段. 下面是一段html代码,根据代码来说明标准事件 ...
- Mybatis按顺序获取数据
sql语句select * from producttg where hospitalcode in (1,2,3) 获取到的数据并不是按照条件1,2,3的顺序排列,如果要成下面形式(mybatis ...