当前位置: 移动技术网 > IT编程>开发语言>c# > async and await 的入门基础操作

async and await 的入门基础操作

2019年07月18日  | 移动技术网IT编程  | 我要评论
如果有几个uri,需要获取这些uri的所有内容的长度之和,你会如何做? 很简单,使用webclient一个一个的获取uri的内容长度,进行累加。 也就是说如果有

如果有几个uri,需要获取这些uri的所有内容的长度之和,你会如何做?

很简单,使用webclient一个一个的获取uri的内容长度,进行累加。

也就是说如果有5个uri,请求的时间分别是:1s 2s 3s 4s 5s.

那么需要的时间是:1+2+3+4+5=(6*5)/2=15.

如果采用并行计算的话,结果可能是这样:

image

总时间长度是5s.

为了演示效果,需要下面3个页面:

image

其中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的内容的总长度。

结果如下:

image 

可以看到时间分别是0s,5s,10s,0s ,5s,10s.所以总长度是(0+5+10)*2=30.

可以看到速度很慢,如果有一个网页卡住的话,后面很恐怖的哦

下面演示使用async,await的方式:

第一步:将 vs2010 升级到 vs2010 sp1.

第二步:下载async ctp,进行安装

第三步:为应用程序添加asyncctplibrary引用,如下:

image 

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中,微软为一些类提供了扩展,如下:

image 

webclient的扩展如下:

image

可以看到基本上为每个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 的话:

image

因为 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);
}


运行结果如下:

image 

可以看到使用了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;
}

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网