async and await 简单的入门
如果有几个Uri,需要获取这些Uri的所有内容的长度之和,你会如何做?
很简单,使用WebClient一个一个的获取uri的内容长度,进行累加。
也就是说如果有5个Uri,请求的时间分别是:1s 2s 3s 4s 5s.
那么需要的时间是:1+2+3+4+5=(6*5)/2=15.
如果采用并行计算的话,结果可能是这样:
总时间长度是5s.
为了演示效果,需要下面3个页面:
其中SlowPage 的Page_load代码如下:
protected void Page_Load(object sender, EventArgs e)
{
Thread.Sleep(5000);
}
VerySlowPage的Page_load事件则 Thread.Sleep(10000);
新建控制台程序CAStudy:
首先新建类AsyncDemo:
同步的获取Uris的内容长度代码如下:
public class AsyncDemo
{
public int SumPageSizes(IList<Uri> uris)
{
int total = 0;
foreach (var uri in uris)
{
Console.WriteLine("Thread {0}:Found {1} bytes...{2}",
Thread.CurrentThread.ManagedThreadId, total,DateTime.Now);
var data = new WebClient().DownloadData(uri);
total += data.Length;
}
Console.WriteLine("{0}:Found {1} bytes total {2}",
Thread.CurrentThread.ManagedThreadId, total, DateTime.Now);
return total;
}
}
在这里SumPageSizes 方法,通过foreach循环一个一个的下载数据。
Main函数如下:
public static void Main()
{
List<Uri> uris = new List<Uri>();
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/QuickPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/SlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/VerySlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/QuickPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/SlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/VerySlowPage.aspx"));
AsyncDemo asyncDemo = new AsyncDemo();
int totalSize = asyncDemo.SumPageSizes(uris);
}
Main 函数主要是构造Uri,然后调用AsyncDemo的SumPageSizes方法来获取所有Uri的内容的总长度。
结果如下:
可以看到时间分别是0s,5s,10s,0s ,5s,10s.所以总长度是(0+5+10)*2=30.
可以看到速度很慢,如果有一个网页卡住的话,后面很恐怖的哦
下面演示使用async,await的方式:
第一步:将 VS2010 升级到 VS2010 sp1.
第二步:下载Async CTP,进行安装
第三步:为应用程序添加AsyncCTPLibrary引用,如下:
OK,将上面的SumPageSizes 方法修改如下:
public async Task<int> SumPageSizesAsync2(IList<Uri> uris)
{
var tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri));
var data = await TaskEx.WhenAll(tasks);
return await TaskEx.Run(() =>
{
return data.Sum(s => s.Length);
});
}
在AsyncCTPLibrary.dll中,微软为一些类提供了扩展,如下:
WebClient的扩展如下:
可以看到基本上为每个Download 都增加了一个XXXTaskAsync 的扩展方法。
返回的全部都是Task,
为什么全部都是Task?,因为await 只能wait Task,并且await 只能用在async 标记的方法中,
async 关键字表明这是个异步方法。
第一句:
public async Task<int> SumPageSizesAsync(IList<Uri> uris)
因为我们申明的是一个异步方法,所以要使用async 关键字,SumPageSizesAsync方法返回的结果是int类型,所以返回Task<int>.
第二句:
IEnumerable<Task<Byte[]>> tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri));
获取DownloadDataTaskAsync返回的所有Task。
第三句:
byte[][] data = await TaskEx.WhenAll(tasks);
首先第二句返回的是IEnumerable<Task<Byte[]>> 类型,也就是一个一个的Task<Byte[]> 的任务,使用TaskEx的WhenAll方法可以将这些任务转变成一个Task<Byte[][]> 的任务
使用await关键字意味着Task<Byte[][]> 方法需要等待,等待结束后返回Byte[][]。
第四句:
return await TaskEx.Run<int>(() =>
{
return data.Sum(s => s.Length);
});
TaskEx.Run 返回将使用第三句返回的data,将Byte[][] 的数据进行Sum运算,返回一个Task<int> 的对象,如果不使用await 的话:
因为 async 关键字代表的是异步方法,并且该异步方法返回的结果是int,所以需要再次使用await 关键字:
return await TaskEx.Run<int>(() =>
{
return data.Sum(s => s.Length);
});
修改Main代码如下:
public static void Main()
{
List<Uri> uris = new List<Uri>();
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/QuickPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/SlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/VerySlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/QuickPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/SlowPage.aspx"));
uris.Add(new Uri("http://localhost:57815/AsyncTestPages/VerySlowPage.aspx"));
AsyncDemo asyncDemo = new AsyncDemo();
Console.WriteLine(DateTime.Now);
int totalSize = asyncDemo.SumPageSizesAsync(uris).Result;
Console.WriteLine("TotalSize:{0}, Finished", totalSize);
Console.WriteLine(DateTime.Now);
}
运行结果如下:
可以看到使用了16秒的时间,大致等于理论值15.
有的同学会说,很麻烦!,的确,我也感觉很麻烦,还不如ThreadPool 来的快,不过async,await主要并不是解决这类问题的,它所解决的是异步中的同步,也就是说在某些异步操作中,需要同步的去处理,比如在Silverlight中,
异步获取A –> 异步获取B –> 异步获取C..
如果使用传统的方式则需要:
WebClient webClient = new WebClient();
webClient.DownloadDataCompleted += (s, e) =>
{
// 使用A对象,做些事情。
WebClient webClient2 = new WebClient();
webClient2.DownloadDataCompleted += (s2, e2) =>
{
//使用B对象,做些事情。
};
webClient2.DownloadDataAsync(new Uri("B 的地址"));
};
webClient.DownloadDataAsync(new Uri("A 的地址"));
当然在这里演示的是最丑陋的版本,聪明的同学可以使用Enumerable 来简化异步操作。
如果使用async 和await则可以修改为:
public async Task<int> SumPageSizesAsync3(IList<Uri> uris)
{
int total = 0;
foreach (var uri in uris)
{
WebClient webClient=new WebClient();
var data = await webClient.DownloadDataTaskAsync(uri);
total += data.Length;
}
return total;
}
async and await 简单的入门的更多相关文章
- JavaScript中async和await的使用以及队列问题
宏任务和微任务的队列入门知识,可以参考之前的文章: JavaScript的事件循环机制 宏任务和微任务在前端面试中,被经常提及到,包括口头和笔试题 async && await概念 a ...
- 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...
- 异步async/await简单应用与探究
感谢Marco CAO指出的两点错误,已做出修改与补充 异步函数(async/await)简单应用 .NET Framework4.5提供了针对异步函数语法糖,简化了编写异步函数的复杂度. 下面通过一 ...
- 转:[你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
- [你必须知道的异步编程]C# 5.0 新特性——Async和Await使异步编程更简单
本专题概要: 引言 同步代码存在的问题 传统的异步编程改善程序的响应 C# 5.0 提供的async和await使异步编程更简单 async和await关键字剖析 小结 一.引言 在之前的C#基础知 ...
- 四、C# 5.0 新特性——Async和Await使异步编程更简单
一.引言 .NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作,下面就 ...
- 异步async与await的简单探究
在学习.net core的过程中,到处见到异步的使用,Task.async.await随处可见.有点疑惑,就去了解了下这个过程是怎样的. 下面是一段代码,去看看是怎么执行的吧. 一.看看异步执行的方式 ...
- Promise、async、await在Egret的简单应用
Egret Engnie 5.1.10 Egret Wing 4.1.5 一.Promise.async.await相关知识 Promise介绍 阮一峰 async函数 阮一峰 具体和详细的说明用法可 ...
- C# 异步编程,async与await的简单学习
前提声明:C# 5.0 .NET Framework 4.5 2012-08-15 异步和等待(async和await).调用方信息(Caller Information) (C#版本与.NET版本 ...
随机推荐
- pthread_join和pthread_detach的用法
//从别处拷贝过来的,只作为自己查看方便,原作者不详,请谅解. 一:关于join join join是三种同步线程的方式之一.另外两种分别是互斥锁(mutex)和条件变量(condition vari ...
- web.xml文件的作用及基本配置
Java的web工程中的web.xml文件有什么作用呢?它是每个web工程都必须的吗? 一个web中完全可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的. 那什么时候需要 ...
- Java实现Redis pipeline比较
开始实验这个,是因为Redis实战.pdf上面有例子. 上面用的是 org.jredis包,可是发现这个包不在maven的公共仓库里.需要先下载然后放在本地,导入maven依赖.详见: http:// ...
- RenderMonkey 练习 第二天 【opengl 光照模型】
光照模型 3D渲染中, 物体表面的光照计算公式为: I = 环境光(Iambient) + 漫反射光(Idiffuse) + 镜面高光(Ispecular); 其中,环境光(ambient)计算公式为 ...
- scala之Actors
这多半是因为actor是共享线程,所以阻塞线程会导致其他线程获取不到线程.
- KRBTabControl
This article explains how to make a custom Windows Tab Control in C#. Download demo project - 82.4 K ...
- 用户手册是Yasm汇编
本文档的用户手册是Yasm汇编. 它是介绍和通用所有Yasm用户参考. 英文的参考:http://www.cnblogs.com/coryxie/p/3959888.html 1 .介绍 Yasm b ...
- C# 深入理解堆栈、堆在内存中的实现
尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(GarbageCollection),但是我们还是应该了解它们,以优化我们的应用程序.同时,还需要具备一些基础的内存管理工作机制 ...
- 算法笔记_124:密码脱落(Java)
一 问题描述 X星球的考古学家发现了一批古代留下来的密码.这些密码是由A.B.C.D 四种植物的种子串成的序列.仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串).由于年代久远,其中 ...
- 启动ActiveMQ时报端口被占用异常
配置好ActiveMQ后,前几次都启动成功.有一天启动时发现启动不成功,查看报错日志发现出现如下提示: Failed to start Apache ActiveMQ (localhost, ID:* ...