问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

全面解析C#中的异步编程

发布网友 发布时间:2022-05-24 12:27

我来回答

1个回答

热心网友 时间:2023-10-13 05:45

  当我们处理一些长线的调用时,经常会导致界面停止响应或者IIS线程占用过多等问题,这个时候我们需要更多的是用异步编程来修正这些问题,但是通常都是说起来容易做起来难,诚然异步编程相对于同步编程来说,它是一种完全不同的编程思想,对于习惯了同步编程的开发者来说,在开发过程中难度更大,可控性不强是它的特点。
  在.NET
Framework5.0种,微软为我们系统了新的语言特性,让我们使用异步编程就像使用同步编程一样相近和简单,本文中将会解释以前版本的Framework中基于回调道德异步编程模型的一些*以及新型的API如果让我们简单的做到同样的开发任务。
  为什么要异步
  一直以来,使用远程资源的编程都是一个容易造成困惑的问题,不同于“本地资源”,远程资源的访问总会有很多意外的情况,网络环境的不稳定机器服务端的故障,会造成很多程序员完全不可控的问题,所以这也就要求程序员需要更多的去保护远程资源的调用,管理调用的取消、超市、线程的等待以及处理线程长时间没响应的情况等。而在.NET中我们通常忽略了这些挑战,事实上我们会有多种不用的模式来处理异步编程,比如在处理IO密集型操作或者高延迟的操作时候不组测线程,多数情况我们拥有同步和异步两个方法来做这件事。可是问题在于当前的这些模式非常容易引起混乱和代码错误,或者开发人员会放弃然后使用阻塞的方式去开发。
  而在如今的.NET中,提供了非常接近于同步编程的编程体验,不需要开发人员再去处理只会在异步编程中出现的很多情况,异步调用将会是清晰的且不透明的,而且易于和同步的代码进行组合使用。
  过去糟糕的体验
  最好的理解这种问题的方式是我们最常见的一种情况:用户界面只拥有一个线程所有的工作都运行在这个线程上,客户端程序不能对用户的鼠标时间做出反应,这很可能是因为应用程序正在被一个耗时的操作所阻塞,这可能是因为线程在等待一个网络ID或者在做一个CPU密集型的计算,此时用户界面不能获得运行时间,程序一直处于繁忙的状态,这是一个非常差的用户体验。
  很多年来,解决这种问题的方法都是做异步花的调用,不要等待响应,尽快的返回请求,让其他事件可以同时执行,只是当请求有了最终反馈的时候通知应用程序让客户代码可以执行指定的代码。
  而问题在于:异步代码完全毁掉了代码流程,回调代理解释了之后如何工作,但是怎么在一个while循环里等待?一个if语句?一个try块或者一个using块?怎么去解释“接下来做什么”?
  看下面的一个例子:
  public
int
SumPageSizes(IList
uris)
  {
  int
total
=
0;
  foreach
(var
uri
in
uris)
  {
  txtStatus.Text
=
string.Format("Found
{0}
bytes...",
total);
  var
data
=
new
WebClient().DownloadData(uri);
  total
+=
data.Length;
  }
  txtStatus.Text
=
string.Format("Found
{0}
bytes
total",
total);
  return
total;
  }
  这个方法从一个uri列表里下载文件,统计他们的大小并且同时更新状态信息,很明显这个方法不属于UI线程因为它需要花费非常长的时间来完成,这样它会完全的挂起UI,但是我们又希望UI能被持续的更新,怎么做呢?
  我们可以创建一个后台编程,让它持续的给UI线程发送数据来让UI来更新自身,这个看起来是很浪费的,因为这个线程把大多时间花在等下和下载上,但是有的时候,这正是我们需要做的。在这个例子中,WebClient提供了一个异步版本的DownloadData方法—DownloadDataAsync,它会立即返回,然后在DownloadDataCompleted后触发一个事件,这允许用户写一个异步版本的方法分割所要做的事,调用立即返回并完成接下来的UI线程上的调用,从而不再阻塞UI线程。下面是第一次尝试:
  public
void
SumpageSizesAsync(IList
uris)
  {
  SumPageSizesAsyncHelper(uris.GetEnumerator(),
0);
  }
  public
void
SumPageSizesAsyncHelper(IEnumerator
enumerator,
int
total)
  {
  if
(enumerator.MoveNext())
  {
  txtStatus.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
  {
  txtStatus.Text
=
string.Format("Found
{0}
bytes
total",
total);
  }
  }
  然后这依然是糟糕的,我们破坏了一个整洁的foreach循环并且手动获得了一个enumerator,每一个调用都创建了一个事件回调。代码用递归取代了循环,这种代码你应该都不敢直视了吧。不要着急,还没有完

  原始的代码返回了一个总数并且显示它,新的一步版本在统计还没有完成之前返回给调用者。我们怎么样才可以得到一个结果返回给调用者,答案是:调用者必须支持一个回掉,我们可以在统计完成之后调用它。
  然而异常怎么办?原始的代码并没有关注异常,它会一直传递给调用者,在异步版本中,我们必须扩展回掉来让异常来传播,在异常发生时,我们不得不明确的让它传播。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
爱情的句子高质量文案句子 干妹妹对我"久伴你"是什么意思 陪她一辈子的文案汇总123句 蜂窝移动通信笔记2——调制 通信系统的带宽和频率分析 汽车座椅头枕应该调到什么位置 老面馒头和酵母馒头的区别 老面馒头与酵母馒头哪个好 2024财富中国500强最赚钱40家公司揭晓 2024中国500强盈利排名榜一览 2024全球银行1000强中国名单2024世界银行1000强中国哪些上榜 品牌榜:2024年中国十大银行排行榜 投票结果公布【新】 保集半岛周围有工商银行吗?星期日上班吗 金华汽车南站到金华火车南站乘几路公交车 南昌火车西站到象湖新区保集半岛路线查询 金莎二路保集半岛到南昌西火车站打车多少钱 金华汽车南站离金华火车西站有多远?方便吗?打的多少钱? 金华汽车南站到浙江交通技师学院的公交车在那里坐 江西南昌象湖经济开发区金沙2路保集半岛二期属于哪个管辖区 江西南昌东新乡保集半岛二期小区,是不是很多搞传销的团伙 谁知道龙港哪有卖港行的NOKIA 【保集半岛3期】周边有几家KTV? 南昌象湖保集半岛三期离向塘江西服装学院多远 龙港哪里有别墅 龙港一小网站 龙港散打 光纤MZI一般多长 【车主点评:诚意满满的小轿跑奥迪A5】 【车主点评:奥迪A5 外观优雅运动 既拉风又实用 绝对是年轻人的选择】 光缆3米渗水 是在米数3米的地方渗水吗? 刚考过ccnp,准备学习ccie的课程,麻烦各位推荐下北京的好培训机构啊 【车主点评:奥迪A5 你的优雅永不过时】 异步编程的应用:什么情况下会用到异步编程 为什么女人那么喜欢购物? 女生在购物的时候,她们的智商会变得更高还是更低? 女人购物欲望突然消退了,这是什么原因? 大疆mini2有没有补光灯 女生在购物的时候为什么会很快乐? Ipadmini2和ipadAir处理器都是A7的性能有什么差别呢!为什么贵那么多是不是就是屏幕大 为什么女人购物心情会变好?因为女人很物质么? 请问linux下C编程多线程同步和异步的区别,如何能实现程序的同步和异步编程 该工作还是应该读研究生呢? 美国用什么语言做网站 男朋友说,不要太想我了,该工作工作什么意思,是不是不在乎我了? 做网站,美国主机、香港主机与大陆主机的区别。请详细? 是二战还是该工作? 应聘时被问到该工作对你有哪些吸引力 或者你对比有什么想法 该怎么回答好 我想建个网站,用户都是美国华人~可以吗?在中国建站给在美国的中国人使用~要怎么做 诗词分别起源于哪个朝代 该工作性格内向咋办 谁能告诉我做网站用美国空间还是香港空间换是韩国空间,我在网上看了好多,眼睛都花了? 在该工作的范围内还让你干其他的属不属于违规