解析使用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
投稿

猜你喜欢

  • C#获取局域网MAC地址的简单实例

    2022-08-04 11:26:12
  • tcp、udp、ip协议分析_动力节点Java学院整理

    2023-05-17 18:00:17
  • JSON序列化Redis读取出错问题解决方案

    2022-10-13 18:57:50
  • Android中URLEncoder空格被转码为"+"号的处理办法

    2022-02-09 17:58:12
  • java实现简单超市管理系统

    2022-04-03 07:41:04
  • executor包执行器功能

    2023-07-26 21:07:36
  • opencv3/C++图像滤波实现方式

    2023-06-23 15:37:08
  • 详解SpringBoot和SpringBatch 使用

    2023-08-17 19:00:38
  • Ubuntu中为Android简单介绍硬件抽象层(HAL)

    2022-10-27 21:12:45
  • 深入了解Java线程池的原理使用及性能优化

    2023-02-17 22:35:31
  • Winform 实现进度条弹窗和任务控制

    2023-06-20 04:27:09
  • Android简单创建一个Activity的方法

    2023-01-22 12:39:53
  • C#实现chart控件动态曲线绘制

    2022-01-22 19:10:11
  • C# 7.2中结构体性能问题的解决方案

    2022-08-12 23:04:26
  • C#难点逐个击破(3):params数组参数

    2022-01-17 14:40:22
  • 解决SpringMVC拦截器path路径的坑

    2023-03-24 17:02:01
  • Android利用AsyncTask异步类实现网页内容放大缩小

    2022-11-28 05:34:47
  • ResultSet如何动态获取列名和值

    2022-01-16 15:54:01
  • SpringBoot之@Value获取application.properties配置无效的解决

    2023-09-15 22:37:55
  • Jackson中json格式的字符串与对象的互相转换方式

    2022-01-29 03:31:07
  • asp之家 软件编程 m.aspxhome.com