欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解析使用enumerator模式简化异步操作的详解

程序员文章站 2023-12-16 23:48:04
先看一段同步代码:public int sumpagesizes(ilist uris) {     int total...

先看一段同步代码:

public int sumpagesizes(ilist<uri> uris) {
    int total = 0;
    foreach (var uri in uris) {
        statustext.text = string.format("found {0} bytes ...", total);
        var data = new webclient().downloaddata(uri);
        total += data.length;
    }
    statustext.text = string.format("found {0} bytes total", total);
    return total;
}
这段代码比较简单,使用同步方式一个一个的获取uri的data,然后进行统计。

如果要使用异步方式一个一个的统计,那应该如何计算呢?

我以前演示过一段丑陋的代码大致如下:
 
webclient webclient = new webclient();
 webclient.downloaddatacompleted += (s, e) =>
 {
     // 使用a对象,做些事情。
     webclient webclient2 = new webclient();
     webclient2.downloaddatacompleted += (s2, e2) =>
     {
         //使用b对象,做些事情。
        // 递归的去 downloaddataasync。
     };
     webclient2.downloaddataasync(new uri("b 的地址"));
 };
 webclient.downloaddataasync(new uri("a 的地址"));

当然如果你确定只有两个地址的话,这种方法未尝不可。如果有多个地址的话,则必须递归的调用了。

如何使用enumerator来简化异步操作:

public void sumpagesizesasync(ilist<uri> uris) {
    sumpagesizesasynchelper(uris.getenumerator(), 0);
}
private void sumpagesizesasynchelper(ienumerator<uri> enumerator, int total) {
    if (enumerator.movenext()) {
        statustext.text = string.format("found {0} bytes ...", total);
        var client = new webclient();
        client.downloaddatacompleted += (sender, e) => {
            sumpagesizesasynchelper(enumerator, total + e.result.length);
        };
        client.downloaddataasync(enumerator.current);
    }
    else {
        statustext.text = string.format("found {0} bytes total", total);
        enumerator.dispose();
    }
}

通过sumpagesizesasynchelper ,可以实现异步调用a->异步调用b->异步调用c..的方式。
首先解释下为什么可以,假设uris 有a,b,c.

sumpagesizesasynchelper(uris.getenumerator(), 0);

方法先调用a,因为a后面还有b,所以enumerator.movenext()返回true,
接着在downloaddatacompleted事件结束后,调用b,同样,因为b后面还有c,
所以enumerator.movenext() 继续返回true,接着在downloaddatacompleted事件后调用c。
在调用c结束后,因为c后面没有了,所以enumerator.movenext() 返回false,
也可以认为全部都下载完毕了。所以返回最终的结果。

解析使用enumerator模式简化异步操作的详解

 

解析使用enumerator模式简化异步操作的详解


如果使用async 和await来实现的话,代码如下:

public async task<int> sumpagesizesasync2(ilist<uri> uris)
{
    int total = 0;
    char chartext = 'a';
    foreach (var uri in uris)
    {
       var data = await new webclient().downloaddatataskasync(uri);
        total += data.length;
        console.writeline("thread id: {0}:调用{1}的地址 found {2} bytes...{3}",
            thread.currentthread.managedthreadid, chartext, total, datetime.now);
        chartext = convert.tochar(chartext + 1);
    }
    console.writeline("thread id: {0}:全部完成,found {1} bytes total {2}",
        thread.currentthread.managedthreadid, total, datetime.now);
    return total;
}

上一篇:

下一篇: