使用enumerator模式简化异步操作

简介:

先看一段同步代码:

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

这段代码比较简单,使用同步方式一个一个的获取UriData,然后进行统计。

 

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

我以前演示过一段丑陋的代码大致如下:

 

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

也可以认为全部都下载完毕了。所以返回最终的结果。

 

image

 

image

 

如果使用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;

}






本文转自LoveJenny博客园博客,原文链接:http://www.cnblogs.com/LoveJenny/archive/2011/11/04/2235241.html,如需转载请自行联系原作者

目录
相关文章
|
3月前
|
前端开发 Java API
vertx学习总结5之回调函数及其限制,如网关/边缘服务示例所示未来和承诺——链接异步操作的简单模型响应式扩展——一个更强大的模型,特别适合组合异步事件流Kotlin协程
本文是Vert.x学习系列的第五部分,讨论了回调函数的限制、Future和Promise在异步操作中的应用、响应式扩展以及Kotlin协程,并通过示例代码展示了如何在Vert.x中使用这些异步编程模式。
63 5
vertx学习总结5之回调函数及其限制,如网关/边缘服务示例所示未来和承诺——链接异步操作的简单模型响应式扩展——一个更强大的模型,特别适合组合异步事件流Kotlin协程
|
8月前
|
前端开发 JavaScript 安全
Promise/A+ 规范详解:打造健壮异步代码的必备知识(上)
Promise/A+ 规范详解:打造健壮异步代码的必备知识(上)
Promise/A+ 规范详解:打造健壮异步代码的必备知识(上)
|
7月前
|
存储 前端开发 JavaScript
回调函数是JavaScript中处理异步编程的常见模式,常用于事件驱动和I/O操作。
【6月更文挑战第27天】回调函数是JavaScript中处理异步编程的常见模式,常用于事件驱动和I/O操作。它作为参数传递给其他函数,在特定条件满足或任务完成后被调用。例如,`asyncOperation`函数接受回调函数`handleResult`,模拟异步操作后,调用`handleResult`传递结果。这样,当异步任务完成时,`handleResult`负责处理结果。
43 1
|
6月前
|
Java
回调函数在异步编程中的作用与实现方式
回调函数在异步编程中的作用与实现方式
|
8月前
|
测试技术
使用 Playwright 复用 Cookie:简化自动化测试的高效方法
Playwright 提供的 Cookie 复用功能允许在不同测试用例间共享会话状态,提高测试效率。通过 `context.set_cookies()` 方法设置共享 Cookie 数据,确保会话在多个测试中保持一致。优点包括节省时间、维持稳定会话,但需注意可能增加测试用例间的依赖。使用此功能可优化自动化测试流程。
|
8月前
|
前端开发
如何处理前端应用程序中的异步操作
前端异步操作常见方法包括回调函数、Promise 和 async/await。回调函数可能导致回调地狱,Promise 提供了更好的错误处理和链式调用,而 async/await 则基于 Promise,以同步风格处理异步任务,提高代码可读性。根据需求和喜好选择相应方法,以实现更可靠、易维护的代码。
|
8月前
|
前端开发 安全
Promise/A+ 规范详解:打造健壮异步代码的必备知识(下)
Promise/A+ 规范详解:打造健壮异步代码的必备知识(下)
Promise/A+ 规范详解:打造健壮异步代码的必备知识(下)
|
缓存 负载均衡 网络协议
【Socket】两种高效事件处理模式&并发模式
【Socket】两种高效事件处理模式&并发模式
|
消息中间件 Java 数据库
实现异步编程的方式
实现异步编程的方式
|
PHP 数据安全/隐私保护
Laravel 8 新特性之:优化维护模式、闭包分发和链式catch
Laravel 8 通过引入 Laravel Jetstream,模型工厂类,迁移压缩,队列批处理,改善速率限制,队列改进,动态 Blade 组件,Tailwind 分页视图, 时间测试助手,artisan serve 的改进,事件监听器的改进,以及各种其他错误修复和可用性改进,对 Laravel 7.x 继续进行了改善。
147 0

热门文章

最新文章