Task异步编程
Task异步编程中,可以实现在等待耗时任务的同时,执行不依赖于该耗时任务结果的其他同步任务,提高效率。
1、Task异步编程方法签名及返回值:
a) 签名有async 修饰符
b) 方法名以 Async 结尾(良好的编码习惯)
根据约定,将“Async”追加到具有 async 修饰符的方法名称。如果某一约定中的事件、基类或接口协定建议其他名称,则可以忽略此约定。例如,你不应重命名常用事件处理程序,例如 btnOpen_Click。
c) 返回类型如下:
- 如果方法有操作数为TResult 类型的返回语句,则为 Task<TResult>;
- 如果你的方法没有返回语句或具有没有操作数的返回语句,则为 Task;
- 如果你编写的是异步事件处理程序,则为 void。
d) 方法通常包含至少一个 await 表达式,该表达式标记一个点,在该点上,直到等待的异步操作完成,方法才能继续。 同时,将方法挂起,并且控制权将返回到方法的调用方。
举例如下:
private static async Task<int> OperateAsync()
2、 举例分析:
static void Main(string[] args)
{
Test1.DoClickAsync();
Console.WriteLine("不等待异步方法,直接执行");
Console.ReadKey();
}
public class Test1
{
public static async void DoClickAsync()
{
Task<int> result = OperateAsync();
Console.WriteLine("从OperateAsync方法中控制权限返回调用方DoClickAsync");
int resultValue = await result;
Console.WriteLine("耗时操作结果" + resultValue.ToString());
} private static async Task<int> OperateAsync()
{
HttpClient client = new HttpClient(); //执行异步方法 GetStringAsync
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com"); //由于下面的非异步方法不依赖上面异步方法结果,因此可以先执行,假设在这里执行一些非异步的操作
DoIndependentWork(); //等待操作挂起方法 OperateAsync,直到 getStringTask 完成,OperateAsync 方法才会继续执行
//同时,控制将返回到 OperateAsync 方法的调用方,直到 getStringTask 完成后,将在这里恢复控制。
//然后从 getStringTask 拿到字符串结果
string urlContents = await getStringTask; Console.WriteLine("方法OperateAsync");
//返回字符串的长度(int 类型)
return urlContents.Length; } private static void DoIndependentWork()
{
for (int i = ; i < ; i++)
{
Console.WriteLine("主线程执行内容" + i);
Thread.Sleep();
}
}
}
3、步骤分析:
- Main主函数,调用并等待异步方法DoClickAsync;
- DoClickAsync方法调用并等待异步方法OperateAsync;
- 异步方法OperateAsync调用HttpClient对象并调用它的GetStringAsync异步方法来下载网站内容
- 假设GetStringAsync中发生了某种情况,该情况挂起了它的进程。可能必须等待网站下载或一些其他阻塞的活动。为避免阻塞资源,GetStringAsync 会将控制权出让给其调用方 OperateAsync。GetStringAsync返回Task,其中TResult为字符串,并且OperateAsync将任务分配给getStringTask变量。该任务表示调用GetStringAsync的正在进行的进程,其中承诺当工作完成时产生实际字符串值。
- 由于尚未等待getStringTask,因此,OperateAsync可以继续执行不依赖于 GetStringAsync得出最终结果的其他任务。该任务由对同步方法 DoIndependentWork 的调用表示。
- DoIndependentWork 是完成其工作并返回其调用方的同步方法。
- OperateAsync 已完成工作,可以不受 getStringTask 的结果影响。 接下来,OperateAsync 需要计算并返回该下载字符串的长度,但该方法仅在具有字符串时才能计算该值。因此,OperateAsync 使用一个 await 运算符来挂起其进度,并把控制权交给调用 OperateAsync 的方法。OperateAsync将 Task<int> 返回至调用方。该任务表示对产生下载字符串长度的整数结果的一个承诺。
【备注】
(1)如果 GetStringAsync(即 getStringTask)在 OperateAsync 等待前完成,则控制权会保留在 OperateAsync 中。 如果异步调用过程 (getStringTask) 已完成,并且OperateAsync不必等待最终结果,则挂起然后返回到 OperateAsync,但这会造成成本的浪费。
(2)在调用方内部(DoClickAsync),处理模式将继续。在等待结果前,调用方可以开展不依赖于OperateAsync结果的其他工作,否则就需等待片刻。DoClickAsync等待 OperateAsync,而 OperateAsync 等待 GetStringAsync。
- GetStringAsync 完成并生成一个字符串结果。 字符串结果不是通过你预期的方式调用 GetStringAsync 所返回的。(请记住,此方法已在前面步骤中返回一个任务。)相反,字符串结果存储在表示完成方法 getStringTask 的任务中。 await 运算符从 getStringTask 中检索结果。赋值语句将检索到的结果赋给 urlContents。
- 当OperateAsync具有字符串结果时,该方法可以计算字符串长度。然后,OperateAsync 工作也将完成,并且等待程序DoClickAsync可继续使用。
4、同步行为和异步行为差异:
- 同步行为,当其工作完成时会返回一个同步方法;
- 异步行为,当其工作挂起时,异步方法会返回一个任务值。在异步方法最终完成其工作时,任务会标记为已完成,而结果(如果有)将存储在任务中。
5、详谈返回类型:
在.NET 中,异步方法通常返回 Task 或 Task<TResult>。在异步方法中,await运算符应用于通过调用另一个异步方法返回的任务。
1、如果方法包含指定类型 TResult 的操作数的return语句,则将 Task<TResult> 指定为返回类型。
2、如果方法不含任何 return 语句或包含不返回操作数的 return 语句,则将Task用作返回类型。
【备注】
每个返回的任务表示正在进行的工作。任务可封装有关异步进程状态的信息,如果未成功,则最后会封装来自进程的最终结果或进程引发的异常。
3、异步方法还可以是具有void返回类型。该返回类型主要用于定义需要void返回类型的事件处理程序。异步事件处理程序通常用作异步程序的起始点。无法等待具有void返回类型的异步方法,并且一个void返回值的调用方无法捕获该方法引发的任何异常。
下面的示例演示如何声明并调用可返回 Task 或 Task<TResult> 的方法。
static void Main(string[] args)
{
DoMethodAsync();
Console.ReadKey();
} private static async void DoMethodAsync()
{
//调用Method1Async
/*方式一*/
Task<Guid> t1 = Method1Async();
Guid guid1 = t1.Result;
Console.WriteLine("调用Method1Async方式一操作结果" + guid1.ToString());
/*方式二*/
Guid guid2 = await Method1Async();
Console.WriteLine("调用Method1Async方式二操作结果" + guid2.ToString()); //调用Method2Async
/*方式一*/
Task t2 = Method2Async();
await t2;
/*方式二*/
await Method2Async();
} //返回Task<TResult>类型
static async Task<Guid> Method1Async() //Task<Guid>
{
Console.WriteLine("调用Method1Async");
var result = Guid.NewGuid(); await Task.Delay(); //这里返回一个 Guid 的类型
return result;
} //返回Task类型
static async Task Method2Async() //Task
{
Console.WriteLine("调用Method2Async");
//Do... await Task.Delay(); //Do... //这里没有 return 语句
}
6、总结:
1、标记的异步方法(通过使用 async 修饰符)可以使用 await 来指定悬挂点。await 运算符通知编译器,异步方法只有直到等待的异步过程完成才能继续通过该点。同时,控制权将返回至异步方法的调用方。
2、异步方法通常包含 await 运算符的一个或多个匹配项,但缺少 await 表达式不会导致编译器错误。如果异步方法未使用 await 运算符标记悬挂点,则该方法将作为同步方法执行,不管异步修饰符(async)如何。编译器将为此类方法发布一个警告。
7、参考:
http://www.cnblogs.com/liqingwen/p/5922573.html
Task异步编程的更多相关文章
- c#中的Task异步编程
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index翻译 1. 引入 Task异步 ...
- 新手浅谈C#Task异步编程
Task是微软在.net framework 4.0发布的新的异步编程的利器,当然4.5新增了async.await,这儿我们先说Task相关. 在实际编程中,我们用的较多的是Task.Task.Fa ...
- 新手浅谈Task异步编程和Thread多线程编程
初学Task的时候上网搜索,看到很多文章的标题都是task取代thread等等相关,我也一直以为task和thread是一类,其实task是.net4.0提出的异步编程,在之前.net1.0有dele ...
- Task 异步编程测试案例及基础应用说明
对于多线程,我们经常使用的是Thread.在我们了解Task之前,如果我们要使用多核的功能可能就会自己来开线程,然而这种线程模型在.net 4.0之后被一种称为基于“任务的编程模型”所冲击,因为tas ...
- Task异步编程,刨根到底
1. 编译器到底对await做了什么 await 一个异步操作的时候,实际上编译器会创建一个状态机,这个状态机包含了调用者的上下文变量,状态机使用yield迭代器实现,状态机由clr调度,每次运行都会 ...
- .NET 4.5 Task异步编程学习资料
参考资料: 1. http://www.cnblogs.com/heyuquan/archive/2013/04/18/3028044.html
- 『审慎』.Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
异步Task简单介绍 本标题有点 哗众取宠,各位都别介意(不排除个人技术能力问题) —— 接下来:我将会用一个小Demo 把 本文思想阐述清楚. .Net 4.0 就有了 Task 函数 —— 异步编 ...
- Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历
Net4.6 Task 异步函数 比 同步函数 慢5倍 踩坑经历 https://www.cnblogs.com/shuxiaolong/p/DotNet_Task_BUG.html 异步Task简单 ...
- 多线程之异步编程: 经典和最新的异步编程模型, IAsyncInfo 与 Task 相互转换
经典的异步编程模型(IAsyncResult) 最新的异步编程模型(async 和 await) 将 IAsyncInfo 转换成 Task 将 Task 转换成 IAsyncInfo 示例1.使用经 ...
随机推荐
- 本周psp个人作业
计划--用一天的时间来做这个项目 需求分析--作为一个观众,我想要知道每局的比分,以便我更了解比赛情况. 生成设计文档--用类图来进行说明. 设计复审---无 代码规范--3H 具体设计--建立数据库 ...
- MongoDB学习笔记
MongoDB的学习目标(v.3.4.0) 1.MongoDB的概念,非关系型数据库NOSQL 2.学会MongoDB的搭建 3.熟悉MongoDB使用 最基本的文档的读写更新删除 各种不同类型的索引 ...
- Cocos2dx
初玩Cocos2dx,多多包涵. 感觉版本之间的差异比较大,相对前面的版本来说,3.X更容易上手,更方便了. 一.安装python.我的python-2.7.3.配置环境变量 系统变量里:在Path里 ...
- ajax循环读取json多维数组
test.json: { "one": [ { "name": "黑默丁格", "car": "鲁LLL608 ...
- 我的基于asp.net mvc5 +mysql+dapper+easyui 的Web开发框架(0)
前些日子工作不太忙,自己开发了一个web框架用于以后快速开发,现在分享出来. 系统没有使用各种复杂的东西,也没有太多的层次,有兴趣的可以研究一下.
- 小白请教几个关于Java虚拟机内存分配策略的问题
最近在看周志明所著的<深入理解Java虚拟机>,有几个问题不太明白,希望对虚拟机有研究的哥们儿帮我解答一下.先说一下我进行试验的环境: 操作系统:Mac OS X 10.11.6 EI C ...
- Delphi的分配及释放---New/Dispose, GetMem/FreeMem及其它函数的区别与相同
转载自:http://www.cnblogs.com/qiusl/p/4028437.html?utm_source=tuicool 我估摸着内存分配+释放是个基础的函数,有些人可能没注意此类函数或细 ...
- 优化Linux内核参数
转自:http://www.centoscn.com/CentOS/config/2013/0804/992.html vim /etc/sysctl.conf 1.net.ipv4.tcp_max_ ...
- 解决报错 ora-00704 ora-00604 ora-00942 启动不了数据库问题
早上海南的同事打电话说他们的审计库连不上了启动也报错,问了下最近做了些什么操作,答复是之前添加了一次磁盘. 猜测是添加磁盘启动后/dev/sdx顺序出错,或者没有正常的关闭数据库导致数据库无法正常启动 ...
- 【CentOS】LAMP
文章需要整合,学习需要归纳,博主把一连四篇的LAMP合并成为一片长篇的大部头,并梳理了一下他们的关系,希望对各位有所帮助 最近一次更新:2016年12月21日21:38:31 本文为博主JerryCh ...