当前位置:  编程技术>.net/c#/asp.net

async and await 的入门基础操作

    来源: 互联网  发布时间:2014-10-20

    本文导语:  如果有几个Uri,需要获取这些Uri的所有内容的长度之和,你会如何做? 很简单,使用WebClient一个一个的获取uri的内容长度,进行累加。 也就是说如果有5个Uri,请求的时间分别是:1s 2s 3s 4s 5s. 那么需要的时间是:1+2+3+4+5=(6*5)/2=...

如果有几个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 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 uris = new List();

    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 SumPageSizesAsync2(IList 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 SumPageSizesAsync(IList uris)

因为我们申明的是一个异步方法,所以要使用async 关键字,SumPageSizesAsync方法返回的结果是int类型,所以返回Task.


第二句:

IEnumerable tasks = uris.Select(uri => new WebClient().DownloadDataTaskAsync(uri));

获取DownloadDataTaskAsync返回的所有Task。

第三句:

byte[][] data = await TaskEx.WhenAll(tasks);

首先第二句返回的是IEnumerable 类型,也就是一个一个的Task 的任务,使用TaskEx的WhenAll方法可以将这些任务转变成一个Task 的任务


使用await关键字意味着Task 方法需要等待,等待结束后返回Byte[][]。

第四句:

return await TaskEx.Run(() =>

            {

                return data.Sum(s => s.Length);

            });

TaskEx.Run 返回将使用第三句返回的data,将Byte[][] 的数据进行Sum运算,返回一个Task 的对象,如果不使用await 的话:



因为 async 关键字代表的是异步方法,并且该异步方法返回的结果是int,所以需要再次使用await 关键字:

return await TaskEx.Run(() =>
            {
                return data.Sum(s => s.Length);
            });

修改Main代码如下:

代码如下:

public static void Main()
{
    List uris = new List();

    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 SumPageSizesAsync3(IList uris)
{
    int total = 0;
    foreach (var uri in uris)
    {
        WebClient webClient=new WebClient();
        var data = await webClient.DownloadDataTaskAsync(uri);
        total += data.Length;
    }
    return total;
}


    
 
 

您可能感兴趣的文章:

 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • java命名空间javax.transaction.xa类xaexception的类成员方法: xaer_async定义及介绍
  • WP Async Task
  • 异步 HTTP 客户端开发包 android-async-http iis7站长之家
  • async-profile
  • async-json-library
  • Async Http Client
  • Xlib: unexpected async reply
  • 异步 HTTP 客户端开发包 android-async-http
  • async和DOM Script文件加载比较
  • 关于async和await的一些误区实例详解
  • .net4.5使用async和await异步编程实例
  • .NET中的async和await关键字使用及Task异步调用实例


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3