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

时间:2021-10-08 01:44:54 

先看一段同步代码:

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;
}

标签:enumerator,异步操作
0
投稿

猜你喜欢

  • SpringBoot接口中如何直接返回图片数据

    2023-04-22 13:10:24
  • Java调用接口如何获取json数据解析后保存到数据库

    2023-11-16 15:01:36
  • 关于HashMap相同key累加value的问题

    2022-02-13 13:32:18
  • C#判断ip地址是否可以ping的通

    2021-08-29 10:53:13
  • java压缩zip文件中文乱码问题解决方法

    2022-12-20 11:14:25
  • C# 语音功能的实现方法

    2023-03-15 13:40:51
  • SpringBoot 接口开发教程(httpclient客户端)

    2023-05-08 17:31:34
  • c#根据文件类型获取相关类型图标的方法代码

    2022-07-30 10:56:41
  • java实现图书馆管理系统

    2023-12-10 15:50:29
  • mybatis拦截器与分页插件实例教程

    2021-11-16 15:41:48
  • Android实现腾讯新闻的新闻类别导航效果

    2023-07-29 04:17:46
  • JAVA实现账户取款和存款操作

    2023-08-22 16:31:45
  • js+java实现登录滑动图片验证

    2022-02-21 21:17:17
  • 详解WPF如何使用必应地图控件

    2021-07-29 19:01:27
  • spring boot微服务场景下apollo加载过程解析

    2022-05-20 13:55:32
  • 使用SpringBoot实现微服务超时重试模式的示例

    2021-12-28 13:58:45
  • Unity3D实现批量下载图片功能

    2021-07-03 13:00:14
  • Java servlet、filter、listener、interceptor之间的区别和联系

    2023-11-02 15:32:17
  • Java高并发之CyclicBarrier的用法详解

    2023-11-17 16:27:57
  • Gradle 依赖切换源码实践示例详解

    2023-02-21 13:21:44
  • asp之家 软件编程 m.aspxhome.com