时间:2021-05-19
先看一段同步代码:
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,
也可以认为全部都下载完毕了。所以返回最终的结果。
如果使用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;
}
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
在.NETCore中使用异步编程已经很普遍了,你在项目中随处可见async和await,它简化了异步操作,允许开发人员,使用同步的方式编写异步代码,你会发现在大
协程是一种并发设计模式,您可以在Android上使用它来简化异步执行的代码。Kotlin1.3版本添加了Coroutines,并基于其他语言的既定概念。在And
一、同步加载与异步加载的形式1.同步加载我们平时最常使用的就是这种同步加载形式:同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续
AndroidAsyncTask实现异步处理任务的方法详解在开发Android应用时必须遵守单线程模型的原则:AndroidUI操作并不是线程安全的并且这些操作
微信小程序中使用Promise进行异步流程处理的实例详解我们知道,JavaScript是单进程执行的,同步操作会对程序的执行进行阻塞处理。比如在浏览器页面程序中