异步编程

概述

  在事先写的意气风发篇有关async和await的前生今生的稿子以往,大家仿佛在async和await提升网址拍卖技艺方面还应该有大器晚成对疑云,腾讯网自身也做了成都百货上千的尝尝。前几日大家再来回答弹指间那几个主题材料,同期大家会做一个async和await在WinForm中的尝试,并且相比较在4.5事先的异步编制程序方式APM/EAP和async/await的界别,最后我们还恐怕会追究在差异线程之间互相的标题。

  IIS存在着管理手艺的问题,不过WinForm却是UI响应的主题材料,而且WinForm的UI线程至始至终都以同叁个,所以两个之间有早晚的区分。有人会问,未来还恐怕有人写WinForm吗?好呢,它确是三个相比较老的事物吧,比不上WPF炫,技艺也比不上WPF先进,不过从架构层面来说,不管是Web,依旧WinForm,又也许WPF,Mobile,这一个都只是表现层,不是么?未来的巨型系统日常桌面客商端,Web端,手提式有线电话机,平板端都会提到,那也是干吗会有应用层,服务层的留存。大家在这里评论的ASP.NET
MVC,WinForm,WFP,Android/IOS/WP
都以显现层,在表现层我们应有只管理与“表现”相关的逻辑,任何与事务有关的逻辑应该都以坐落下层管理的。关于架构的难点,大家前面再逐月深远,此外别说笔者未曾提示您,大家明天还有大概会看见.NET中另三个生龙活虎度老去的技巧Web
Service。

  还得唤醒您,文章内容有一点长,涉及的知识点比超多,所以,小编引入:”先顶后看“
,先顶后看是21世纪看长篇的首荐之道,是上佳关系的发端,想精通是怎会让你非常吧?想清楚干什么香水之都前几日会下那样大的雨么?请记住先顶后看,你顶的不是笔者的篇章,而是大家冒着小雨还要去上班的可贵精气神儿!先顶后看,你值得全部!

目录

async/await怎样提高IIS管理本领

  首先响应技能并不完全部都以说我们先后质量的难点,有时候恐怕您的次序未有别的难题,并且留意经过优化,可是响应技术仍然不曾上来,网址品质深入分析是一个复杂的活,一时候只可以靠经历和不仅的尝尝本事达到规定的标准相比较好的效力。当然大家明日研究的要害是IIS的管理本事,或然也可能正是IIS的质量,但未有代码自身的性质。即便async/await能够增加IIS的拍卖本领,不过对于客商来讲一切页面从发起呼吁到页面渲染完结的那么些时刻,是不会因为大家加了async/await之后发出多大转移的。

  此外异步的ASP.NET并非唯有async/await工夫够做的,ASP.NET在Web
Form时期就已经有异步Page了,包蕴ASP.NET
MVC不是也会有异步的Controller么?async/await
很新,相当帅,不过它也只是在本来一技能底工上做了有些改革,让程序猿们写起异步代码来更便于了。大家常说微软赏识老生常谈,起码我们要见到这一个新瓶给我们带给了什么样,不管是别的成品,都不容许豆蔻梢头开头就很完备,所以持续的迭代立异,也得以说是生机勃勃种科学做事的法门。

ASP.NET并行管理的步骤

   ASP.NET是怎么在IIS中央银行事的一文已经很详细的介绍了三个伸手是怎么着从客商端到服务器的HTTP.SYS最后走入CLRubicon举行拍卖的(生硬提出不打听这一块的同班先看那篇随笔,有利于你明白本小节卡塔尔,不过富有的步骤都以依据三个线程的借使下进展的。IIS本身就是一个四线程的劳作情形,如若我们从三十二线程的视角来看会发生什么样变动吧?大家首先来看一下上边那张图。注意:大家上面包车型大巴步调是创建在IIS7.0今后的融会格局根底之上的。(注:下边那张图在dudu的唤起之后,重新做了有的寻觅工作,做了有的改成,w3dt这一步来自于天涯论坛团组织对难点的再三探寻,详细的情况能够点这里

图片 1

  大家再来梳理一下上边的步调:

  1. 负有的乞请最起头是由HTTP.SYS选拔的,HTTP.SYS内部有一个类别维护着那个乞求,那几个队列的request的数量超过一定数量(暗中认可是1000卡塔 尔(阿拉伯语:قطر‎的时候,HTTP.SYS就能够从来回到503场馆(服务器忙卡塔尔,那是我们的首先个阀门。质量计数指标:“Http
    Service Request Queues\CurrentQueueSize
  2. 由w3dt担当把要求从HTTP.SYS
    的行列中放置一个一倡百和端口的队列中,据非官方资料展现该队列长度为能为20(该队列是非公开的,未有文书档案,所以也还未品质流速計卡塔尔国。
  3. IIS
    的IO线程从上一步的行列中获取央求,假设是急需ASP.NET管理的,就能够传递给CLEvoque线程池的Worker 线程,IIS的IO线程继续回到重新做该手续。CL揽胜极光线程池的Worker线程数量是第三个阀门。
  4. 当CL途胜中正在被管理的乞求数据超过一定值(最大并行管理央浼数量,.NET4随后私下认可是5000卡塔尔的时候,从IO线程过来的伸手就不会平素提交Worker线程,而是放到叁个进度池级其余二个队列了,等到那几个数目紧跟于临界角的时候,才会把它再一次提交Worker线程去处理。那是大家的第八个阀门。
  5. 上一步中聊到的百般进度池级其他系列有一个长度的限量,能够由此web.config里面包车型大巴processModel/requestQueueLimit来安装。那能够说也是叁个阀门。当正在处理的数码超过所允许的最大并行管理伏乞数量的时候,我们就能得到503了。可以因此质量计数目的:“ASP.NET
    v4.0.30319\Requests Queued
    ” 来查看该队列的长度。

 哪些因素会垄断(monopoly卡塔 尔(英语:State of Qatar)大家的响应本事

  从地点我们关系了几大阀门中,大家能够吸取上边包车型客车多少个数字调节只怕说影响着大家的响应技巧。

  1. HTTP.SYS队列的长短
  2. CL哈弗线程池最大Worker线程数量
  3. 最大并行管理乞请数量
  4. 进程池等级队列所允许的长短

HTTP.SYS队列的尺寸

  本条小编觉着无需相当解释,暗中认可值是1000。这么些值决计于大家大家前边IIS
IO线程和Worker线程的管理速度,纵然它们八个都处理不了,这些数字再大也并未有用。因为最终他们会被寄放到进度池级其余队列中,所以只会引致内部存款和储蓄器的荒芜。

最大Worker线程数量

  那几个值是足以在web.config中张开安顿的。

图片 2

  maxWorkerThreads: CL福睿斯中真正管理央浼的最大Worker线程数量
  minWorkerThreads:CL奥迪Q5中真正管理央求的细微Worker线程数量

  minWorkerThreads的默许值是1,合理的加大他们得以免止不供给的线程创立和销毁职业。

最大并行处理央求数量

  进程池等级的行列给大家的CLEnclave一定的缓冲,那中间要注意的是,那么些队列尚未进去到CLLAND,所以它不会占用我们托管情形的别样能源,约等于把央浼卡在了CL昂Cora的外侧。大家需求在aspnet.config品级实行安插,我们得以在.net
fraemwork的安装目录下找到它。日常是 C:\Windows\Microsoft.NET\Framework\v4.0.30319
假如你安装的是4.0的话。

图片 3

  maxConcurrentRequestPerCPU:
每一个CPU所允许的最大并行管理乞请数量,当CLLAND中worker线程正在管理的乞请之和超过这些数时,从IO线程过来的乞请就能被放到大家进度池等级的行列中。
  maxConcurrentThreadsPerCPU: 设置为0即禁用。
  requestQueue: 进度池等级队列所允许的尺寸  

async和await 做了什么?

  大家到底要切入核心了,拿ASP.NET
MVC举个例子,要是不利用async的Action,那么势必,它是在多少个Woker线程中施行的。当我们拜谒片段web
service,也许读文件的时候,那个Worker线程就能被打断。假设我们以此Action实行时间总共是100ms,此外访谈web
service花了80ms,理想图景下一个Worker线程生机勃勃秒能够响应12个央求,假诺大家的maxWorkerThreads是10,那大家大器晚成秒内接连可响应伏乞正是100。假如说大家想把那么些可响应央求数升到200怎么办啊?

  有人会说,那还不简单,把maxWorkerThreads调20不就能够了么?
其实大家做也向来不什么样
难题,确实是足以的,并且也真的能起到功效。那大家为啥还要挖空心境的搞什么
async/await呢?搞得脑子都晕了?async/await给大家消亡了怎么难点?它可以在大家拜会web
service的时候把当前的worker线程放走,将它放回线程池,那样它就足以去管理任何的伸手了。等到web
service给我们回去结果了,会再到线程池中从心所欲拿多少个新的woker线程继续往下推行。也等于说大家降低了这部分守候的时间,充份利用了线程。

    大家来对待一下行使async/awit和不行使的情状,

  不应用async/await: 十八个woker线程1s方可拍卖200个伏乞。

  那调换来总的时间的就是 20 * 1000ms =  20000ms,
  个中等待的时光为 200 * 80ms = 16000ms。
  约等于说使用async/await大家最少节省了16000ms的时刻,那贰13个worker线程又会再去管理央求,即便根据每一个央求100ms的拍卖时间大家还足以再追加1伍十几个必要。并且别忘了100ms是遵照同盟情形下,包蕴等待时间在内的基本功上获得的,所以实际上境况大概还要多,当然大家那边未有算上线程切换的年月,所以真实情状中是有某个差距的,不过相应不会异常的大,因为大家的线程都以依据线程池的操作。
  全体结果是21个Worker线程不行使异步的情景下,1s能自理200个央浼,而利用异步的场地下得以拍卖3五15个央求,立马提高十分之七啊!接收异步之后,对于同生机勃勃的号令数量,需求的Worker线程数据会大大减少一半左右,一个线程最少会在堆上分配1M的内部存款和储蓄器,借使是1000个线程那正是1G的体量,尽管内部存款和储蓄器以往便利,不过省着到底是好的嘛,並且更加少的线程是能够减掉线程池在敬性格很顽强在艰难困苦或巨大压力面前不屈线程时爆发的CPU消耗的。另:dudu分享 CL奔驰M级1秒之内只可以创制2个线程。

  注意:以上数据毫无真正测验数据,实际境况一个request的年月也不用100ms,开支在web
service上的岁月也无须80ms,仅仅是给大家二个思路:),所以那其间用了async和await之后对响应本领有多大的晋升和大家本来堵塞在此些IO和网络上的时日是有十分大的关联的。

几点提出

  见到此间,不了然大家有未有收获点什么。首先第一点我们要知道的是async/await不是万能药,不们无法指望光写五个光键字就愿意品质的进级。要牢牢记住,一个CPU在同期段内是一定要实践二个线程的。因而那也是干吗async和await建议在IO大概是网络操作的时候使用。大家的MVC站点访谈WCF或然Web
Service这种现象就可怜的相符利用异步来操作。在上边的例子中80ms读取web
service的年华,大部份时间都以无需cpu操作的,这样cpu能力够被其它的线程利用,假若不是叁个读取web
service的操作,而是三个眼花缭乱总结的操作,这您就等着cpu爆表吧。

  第二点是,除了程序中行使异步,大家地点讲到的关于IIS的布署是相当的重大的,假如应用了异步,请记得把maxWorkerThreads和maxConcurrentRequestPerCPU的值调高试试。

 刚开始阶段对Web service的异步编制程序模式APM

  讲罢大家伟大上的async/await之后,我们来拜见那个技巧很老,然则概念确仍旧三回九转于今的Web
Service。 大家那边所说的指向web
service的异步编制程序形式不是指在劳动器端的web service本人,而是指调用web
service的顾客端。我们精晓对于web service,大家经过增多web
service援用也许.net提供的转换工具就能够更动对应的代理类,能够让我们像调用本地代码同样访谈web
service,而所生成的代码类中对针对每多少个web
service方法生成3个照望的措施,比方说大家的艺术名为DownloadContent,除了那么些情势之外还应该有BeginDownloadContent和EndDownloadContent方法,而那八个正是大家明日要说的早期的异步编程形式APM(Asynchronous
Programming Model)。上边就来拜谒我们web
service中的代码,注意大家今后的花色都以在.NET Framework3.5下促成的。

 PageContent.asmx的代码

public class PageContent : System.Web.Services.WebService
{
    [WebMethod]
    public string DownloadContent(string url)
    {
        var client = new System.Net.WebClient();
        return client.DownloadString(url);
    }
}

  注意大家web
service中的DownloadContent方法调用的是WebClient的联合方法,WebClient也可以有异步方法即:DownloadStringAsync。不过我们要明了,不管服务器是同台仍旧异步,对于客户端的话调用了你这几个web
service都以肖似的,正是得等您回去结果。

  当然,大家也能够像MVC里面包车型地铁代码同样,把大家的服务器端也写成异步的。这获得好处的是丰硕托管web
service的服务器,它的拍卖技巧获得加强,就如ASP.NET同样。假若大家用JavaScript去调用这一个Web
Service,那么Ajax(Asynchronous Javascript +
XML)就是大家顾客端用到的异步编制程序本事。假设是任何的顾客端呢?举例说三个CS的桌面程序?大家要求异步编制程序么?

当WinForm遇上Web Service

  WinForm不像托管在IIS的ASP.NET网址,会有三个线程池管理着七个线程来管理客商的倡议,换个说法ASP.NET网址生来就是根据三十二线程的。可是,在WinForm中,如若我们不刻意使用多线程,那至始至终,都唯有八个线程,称之为UI线程。只怕在有的小型的系统中WinForm非常少提到到多线程,因为WinForm本人的优势就在它是独立运维在客商端的,在品质上和操作性上都会有比一点都不小的优势。所以广大中型Mini型的WinForm系统都以直接就拜谒数据库了,并且大多也唯有多少的传导,什么图片能源那是超级少的,所以等待的时辰是比较短的,基本不用费怎么着脑子去考虑怎么着3秒之内必需将页面展现到客户前边这种难点。

  既然WinForm在品质上有这么大的优势,那它还索要异步吗?

  大家地方说的是中型小型型的WinForm,借使是重型的系统吧?若是WinForm只是此外的比相当的小部分,有如大家文章初阶说的还恐怕有为数不菲任何众多个手提式无线话机顾客端,Web客商端,平板客户端呢?如果客商端相当多招致数据库撑不住如何是好?
想在上游加黄金年代层缓存怎么做?

  拿三个b2b的网址功效比方,客商能够由此网址下单,手提式有线电电话机也能够下单,还足以通过Computer的桌面顾客端下单。在下完单之后要做到交易,仓库储存扣减,发送订单确认布告等等效用,而无论你的订单是由此哪些端完毕的,那个作用大家都要去做,对啊?那大家就无法独立放在WinForm里面了,不然那几个代码在此外的端里面又得全体崭新再逐黄金年代达成,相符的代码放在不一样的地点那只是非凡危殆的,所以就有了大家后来的SOA架构,把那一个功效都分红服务,每种类型的端都以调用服务就足以了。一是足以统生龙活虎爱抚那一个效应,二是能够相当的低价的做扩展,去越来越好的适应效用和架构上的恢宏。比方说像下边那样的多少个种类。

 图片 4

  在上海教室中,Web端固然也是归属大家常常说的服务端(以致是由多台服务器组成的web集合卡塔尔,可是对我们全部系列的话,它也只是一个端而已。对于多个端的话,它本人只管理和客户人机联作的主题材料,其他全部的效果与利益,业务都会付出后来台管理。在大家位置的架构中,应用层都不会直接到位真正业务逻辑相关的管理,而是放到我们更下层数据层去做拍卖。那么应用层首要协理做一些与顾客交互作用的有个别功效,假如手机短信发送,邮件发送等等,并且可以依靠优先级选取是放入队列中稍候管理也许直接调用效率服务及时管理。

  在如此的三个类别中,大家的Web服务器能够,Winform端也好都将只是全种类统中的多少个极端,它们首要的别的是客户和前边服务时期的叁个桥梁。涉及到Service的调用之后,为了给客户能够的客户体验,在WinForm端,大家自然就要思忖异步的难点。 

WinForm异步调用Web Service

  有了像VS那样刚劲的工具为大家转移代理类,大家在写调用Web
service的代码时就能够像调用本地类库雷同调用Web
Service了,我们只要求加上一个Web Reference就能够了。

图片 5

// Form1.cs的代码

private void button1_Click(object sender, EventArgs e)
{
    var pageContentService = new localhost.PageContent();
    pageContentService.BeginDownloadContent(
        "http://jesse2013.cnblogs.com",
        new AsyncCallback(DownloadContentCallback),
        pageContentService);
}

private void DownloadContentCallback(IAsyncResult result)
{
    var pageContentService = (localhost.PageContent)result.AsyncState;
    var msg = pageContentService.EndDownloadContent(result);
    MessageBox.Show(msg);
}

  代码特别的简易,在奉行完pageContentService.BeginDownloadContent之后,大家的主线程就回到了。在调用Web
service前段时间内大家的UI不会被卡住,也不会产出“无法响应这种景况”,大家还能拖动窗体以致做别的的政工。那便是APM的吸重力,可是大家的callback毕竟是在哪个线程中实行的啊?是线程池中的线程么?咋们接着往下看。

APM异步编制程序方式详整

线程问题

  接下去大家正是更进一层的问询APM这种方式是哪些做事的,可是首先我们要回应上边留下来的主题材料,这种异步的编程格局有未有为我们展开新的线程?让代码说话:

private void button1_Click(object sender, EventArgs e)
{
    Trace.TraceInformation("Is current thread from thread pool? {0}", Thread.CurrentThread.IsThreadPoolThread ? "Yes" : "No");
    Trace.TraceInformation("Start calling web service on thread: {0}", Thread.CurrentThread.ManagedThreadId);
    var pageContentService = new localhost.PageContent();
    pageContentService.BeginDownloadContent(
        "http://jesse2013.cnblogs.com",
        new AsyncCallback(DownloadContentCallback),
        pageContentService);
}

private void DownloadContentCallback(IAsyncResult result)
{
    var pageContentService = (localhost.PageContent)result.AsyncState;
    var msg = pageContentService.EndDownloadContent(result);

    Trace.TraceInformation("Is current thread from thread pool? {0}" , Thread.CurrentThread.IsThreadPoolThread ? "Yes" : "No");
    Trace.TraceInformation("End calling web service on thread: {0}, the result of the web service is: {1}",
        Thread.CurrentThread.ManagedThreadId,
        msg);
}

  大家在按键点击的办法和callback方法中分头出口当前线程的ID,以至她们是不是归属线程池的线程,获得的结果如下:

  Desktop4.0.vshost.exe
Information: 0 : Is current thread a background thread? NO
  Desktop4.0.vshost.exe
Information: 0 : Is current thread from thread pool? NO
  Desktop4.0.vshost.exe
Information: 0 : Start calling web service on thread: 9
  Desktop4.0.vshost.exe
Information: 0 : Is current thread a background thread? YES
  Desktop4.0.vshost.exe
Information: 0 : Is current thread from thread pool? YES
  Desktop4.0.vshost.exe
Information: 0 : End calling web service on thread: 14, the result of
the web service is: <!DOCTYPE html>…

  开关点击的方法是由UI直接决定,很引人瞩目它不是三个线程池线程,也不是后台线程。而小编辈的callback却是在贰个起点于线程池的后台线程奉行的,答案宣告了,但是那会给我们带给三个标题,大家地点讲了独有UI线程也足以去立异大家的UI控件,也正是说在callback中大家是不能够更新UI控件的,那大家怎么样让更新UI让顾客知道反馈呢?答案在后边接晓
:),让大家先注意于把APM弄精通。

从Delegate开始

  其实,APM在.NET3.5以前都被周围采取,在WinForm窗体调节中,在叁个IO操作的类库中等等!我们能够比较轻易的找到搭配了Begin和End的格局,更关键的是假诺是有代理的地点,大家都得以行使APM这种格局。我们来看一个非常粗大略的例证:

delegate void EatAsync(string food);
private void button2_Click(object sender, EventArgs e)
{
    var myAsync = new EatAsync(eat);
    Trace.TraceInformation("Activate eating on thread: {0}", Thread.CurrentThread.ManagedThreadId);
    myAsync.BeginInvoke("icecream", new AsyncCallback(clean), myAsync);
}

private void eat(string food)
{
    Trace.TraceInformation("I am eating.... on thread: {0}", Thread.CurrentThread.ManagedThreadId);
}

private void clean(IAsyncResult asyncResult)
{
    Trace.TraceInformation("I am done eating.... on thread: {0}", Thread.CurrentThread.ManagedThreadId);
}

  上边的代码中,大家透过把eat封装成一个信托,然后再调用该信托的BeginInvoke方法完毕了异步的施行。也等于实在的eat方法不是在主线程中举行的,大家能够看输出的结果:

  Desktop4.0.vshost.exe
Information: 0 : Activate eating on thread: 10
  Desktop4.0.vshost.exe
Information: 0 : I am eating…. on thread: 6
  Desktop4.0.vshost.exe
Information: 0 : I am done eating…. on thread: 6

  clean是大家传进去的callback,该方法会在我们的eat方法实行完事后被调用,所以它会和大家eat方法在同二个线程中被调用。我们尽管熟习代理的话就能驾驭,代码实际上会被编写翻译成二个类,而BeginInvoke和EndInvoke方法就是编写翻译器为大家自行加进去的主意,我们不用额外做其余业务,那在开始的一段时代未有TPL和async/await从前(APM从.NET1.0时日就有了卡塔尔国,的确是三个不利的抉择。

双重认知APM

打探了Delegate完结的BeginInvoke和EndInvoke之后,大家再来剖析一下APM用到的这么些对象。
拿咱们Web service的代理类来举个例子,它为大家转变了以下3个议程:

  1. string DownloadContent(string url): 同步方法
  2. IAsyncResult BeginDownloadContent(string url, AsyncCallback
    callback, object asyncState): 异步开头方法
  3. EndDownloadContent(IAsyncResult asyncResult):异步甘休方法

  在大家调用EndDownloadContent方法的时候,假设大家的web

service调用还还没回来,那这时就能用窒碍的法子去拿结果。不过在大家传到BeginDownloadContent中的callback被调用的时候,那操作必然是现已做到了,也正是说IAsyncResult.IsCompleted

true。而在APM异步编程情势中Begin方法总是回到IAsyncResult这一个接口的完结。IAsyncReuslt仅仅富含以下4个属性:

图片 6

  WaitHanlde常常作为意气风发道对象的基类,并且能够应用它来堵塞线程,越多音讯能够参照MSDN.aspx) 。
依赖于IAsyncResult的救助,大家就足以因此以下三种方式去取妥善前所进行操作的结果。

  1. 轮询
  2. 强制等待
  3. 形成布告

  完结文告正是们在”WinForm异步调用WebService”那结中用到的不二等秘书诀,调完Begin方法之后,主线程纵然完毕任务了。我们也不用监督该操作的推行情形,当该操作实践完事后,我们在Begin方法中传进去的callback就能够被调用了,大家得以在分外情势中调用End方法去拿到结果。上面我们再轻松说一下前边二种办法。

//轮询获取结果代码

var pageContentService = new localhost.PageContent();
IAsyncResult asyncResult = pageContentService.BeginDownloadContent(
    "http://jesse2013.cnblogs.com",
    null,
    pageContentService);

while (!asyncResult.IsCompleted)
{
    Thread.Sleep(100);
}
var content = pageContentService.EndDownloadContent(asyncResult);

 // 强制等待结果代码

var pageContentService = new localhost.PageContent();
IAsyncResult asyncResult = pageContentService.BeginDownloadContent(
    "http://jesse2013.cnblogs.com",
    null,
    pageContentService);

// 也可以调用WaitOne()的无参版本,不限制强制等待时间
if (asyncResult.AsyncWaitHandle.WaitOne(2000))
{
    var content = pageContentService.EndDownloadContent(asyncResult);
}
else
{ 
    // 2s时间已经过了,但是还没有执行完   
}

EAP(Event-Based Asynchronous Pattern)

  EAP是在.NET2.0推出的另意气风发种过渡的异步编程模型,也是在.NET3.5未来Microsoft帮忙的大器晚成种做法,为何呢?
假诺大家建一个.NET4.0要么越来越高版本的WinForm项目,再去增加Web
Reference就能够发觉变化的代理类中风流浪漫度远非Begin和End方法了,记住在3.5的时候是双边共存的,你能够选拔随机意气风发种来行使。但是到了.NET4.0自此,EAP成为了您唯豆蔻梢头的选项。(笔者从没品味过手动生成代理类,风野趣的同校能够品尝一下卡塔尔国让我们来看一下在.NET4下,大家是怎么异步调用Web
瑟维斯的。

private void button1_Click(object sender, EventArgs e)
{
    var pageContent = new localhost.PageContent();
    pageContent.DownloadContentAsync("http://jesse2013.cnblogs.com");
    pageContent.DownloadContentCompleted += pageContent_DownloadContentCompleted;
}

private void pageContent_DownloadContentCompleted(object sender, localhost.DownloadContentCompletedEventArgs e)
{
    if (e.Error == null)
    {
        textBox1.Text = e.Result;
    }
    else
    { 
        // 出错了
    }
}

线程难点

  不掌握大家依旧否记得,在APM情势中,callback是施行在另三个线程中,不可能随易的去更新UI。不过借让你留心看一下方面包车型客车代码,大家的DownloadContentCompleted事件绑定的方法中央行政机构接就更新了UI,把再次回到的源委写到了一个文本框里面。通过平等的办法能够开采,在EAP这种异步编制程序格局下,事件绑定的主意也是在调用的不胜线程中试行的。也正是说消逝了异步编制程序的时候UI人机联作的主题材料,何况是在同二个线程中进行。
看看上边包车型大巴代码:

private void button1_Click(object sender, EventArgs e)
{
    Trace.TraceInformation("Call DownloadContentAsync on thread: {0}", Thread.CurrentThread.ManagedThreadId);
    Trace.TraceInformation("Is current from thread pool? : {0}", Thread.CurrentThread.IsThreadPoolThread ? "YES" : "NO");

    var pageContent = new localhost.PageContent();
    pageContent.DownloadContentAsync("http://jesse2013.cnblogs.com");
    pageContent.DownloadContentCompleted += pageContent_DownloadContentCompleted;
}

private void pageContent_DownloadContentCompleted(object sender, localhost.DownloadContentCompletedEventArgs e)
{
    Trace.TraceInformation("Completed DownloadContentAsync on thread: {0}", Thread.CurrentThread.ManagedThreadId);
    Trace.TraceInformation("Is current from thread pool? : {0}", Thread.CurrentThread.IsThreadPoolThread ? "YES" : "NO");
}

  Desktop4.vshost.exe
Information: 0 : Call DownloadContentAsync on thread: 10

  Desktop4.vshost.exe
Information: 0 : Is current from thread pool? : NO

  Desktop4.vshost.exe
Information: 0 : Completed DownloadContentAsync on thread: 10

  Desktop4.vshost.exe
Information: 0 : Is current from thread pool? : NO

async/await 给WinFrom带给了什么样

  假如说async给ASP.NET带给的是管理技巧的增进,那么在WinForm中给程序猿带给的功利则是最大的。大家再也不用因为要兑现异步写回调可能绑定事件了,省事了,可读性也进步了。不相信你看上面我们将调用大家特别web
service的代码在.NET4.5下落成一下:

private async void button2_Click(object sender, EventArgs e)
{
    var pageContent = new localhost.PageContentSoapClient();
    var content = await pageContent.DownloadContentAsync("http://jesse2013.cnblogs.com");

    textBox1.Text = content.Body.DownloadContentResult;
}

  轻巧的三行代码,像写同步代码同样写异步代码,作者想或然那正是async/await的吸重力吧。在await之后,UI线程就足以回来响应UI了,在上头的代码中大家是不曾新线程发生的,和EAP同样得到结果一向就足以对UI操作了。

  async/await犹如真正很好,可是假若大家await后边的代码实行在别的三个线程中会产生哪些工作吗?

private async void button1_Click(object sender, EventArgs e)
{
    label1.Text = "Calculating Sqrt of 5000000";
    button1.Enabled = false;
    progressBar1.Visible = true;

    double sqrt = await Task<double>.Run(() =>
    {
        double result = 0;
        for (int i = 0; i < 50000000; i++)
        {
            result += Math.Sqrt(i);

            progressBar1.Maximum = 50000000;
            progressBar1.Value = i;
        }
        return result;
    });

    progressBar1.Visible = false;
    button1.Enabled = true;
    label1.Text = "The sqrt of 50000000 is " + sqrt;
}

  大家在分界面中放了叁个ProgressBar,同一时候开二个线程去把从1到5000000的平方全体加起来,看起来是多个异常耗费时间的操作,于是大家用Task.Run开了三个新的线程去施行。(注:倘使是纯运算的操作,八线程操作对品质未有多大扶持,我们这里关键是想给UI八个进程展现当前行行到哪一步了。卡塔尔看起来未有啥样难题,我们按F5运转吧!
  Bomb~

图片 7

  当实践到这边的时候,程序就夭亡了,告诉大家”无效操作,只可以从成立porgressBar的线程访问它。“
 那也是大家大器晚成在此以前波及的,在WinForm前后相继中,独有UI主线程手艺对UI进行操作,别的的线程是尚未权限的。接下来我们就来探视,假若在WinForm中贯彻非UI线程对UI调节的换代操作。 

分歧线程之间通信的主题素材

万能的Invoke

  WinForm中相当多的控件包含窗体在内都贯彻了Invoke.aspx)方法,可以流传多个Delegate,那么些Delegate将会被有着丰盛调整的线程所调用,进而制止了跨线程访问的主题材料。

Trace.TraceInformation("UI Thread : {0}", Thread.CurrentThread.ManagedThreadId);
double sqrt = await Task<double>.Run(() =>
{
    Trace.TraceInformation("Run calculation on thread: {0}", Thread.CurrentThread.ManagedThreadId);
    double result = 0;
    for (int i = 0; i < 50000000; i++)
    {
        result += Math.Sqrt(i);
        progressBar1.Invoke(new Action(() => {
            Trace.TraceInformation("Update UI on thread: {0}", Thread.CurrentThread.ManagedThreadId);
            progressBar1.Maximum = 50000000;
            progressBar1.Value = i;
        }));
    }
    return result;
});

  Desktop.vshost.exe Information: 0 : UI
Thread : 9
  Desktop.vshost.exe Information: 0 : Run calculation on
thread: 10
  Desktop.vshost.exe
Information: 0 : Update UI on thread: 9

  Invoke方法比较轻便,大家就不做过多的商量了,可是大家要思虑到一些,Invoke是WinForm完毕的UI跨线程交换方式,WPF用的却是Dispatcher,纵然是在ASP.NET下跨线程之间的联手又怎么做吧。为了合营各类本事平台下,跨线程同步的标题,Microsoft在.NET2.0的时候就引进了小编们上面包车型大巴这么些目的。

SynchronizationContext上下文同步对象

缘何供给SynchronizationContext

  就疑似大家在WinForm中碰到的难点同样,不常候大家要求在八个线程中传递一些数量或许做一些操作到另四个线程。不过在一大半气象下那是分歧意的,出于安全因素的思索,每叁个线程都有它独立的内部存款和储蓄器空间和上下文。因而在.NET2.0,微软坐蓐了SynchronizationContext。

  它首要的效果之一是为大家提供了大器晚成种将有个别行事职务(Delegate)以队列的方法存款和储蓄在多个上下文对象中,然后把这么些上下文对象关系到现实的线程上,当然一时多个线程也足以提到到同三个SynchronizationContext对象。获取当前线程的一块儿上下文对象能够动用SynchronizationContext.Current。同一时候它还为大家提供以下七个艺术Post和Send,分别是以异步和协同的章程将大家位置说的办事职分放到大家SynchronizationContext的行列中。

SynchronizationContext示例

  依旧拿大家地点Invoke中用到的例子举个例子,只是这一次我们不直接调用控件的Invoke方法去立异它,而是写了三个Report的章程特地去更新UI。

double sqrt = await Task<double>.Run(() =>
{
    Trace.TraceInformation("Current thread id is:{0}", Thread.CurrentThread.ManagedThreadId);

    double result = 0;
    for (int i = 0; i < 50000000; i++)
    {
        result += Math.Sqrt(i);
        Report(new Tuple<int, int>(50000000, i));
    }
    return result;
});

  每贰遍操作完事后我们调用一下Report方法,把大家合并要算的数字,以致当前正值测算的数字传给它就能够了。接下来就看大家的Report方法了。

private SynchronizationContext m_SynchronizationContext;
private DateTime m_PreviousTime = DateTime.Now;

public Form1()
{
    InitializeComponent();
    // 在全局保存当前UI线程的SynchronizationContext对象
    m_SynchronizationContext = SynchronizationContext.Current;
}

public void Report(Tuple<int, int> value)
{
    DateTime now = DateTime.Now;
    if ((now - m_PreviousTime).Milliseconds > 100)
    {
        m_SynchronizationContext.Post((obj) =>
        {
            Tuple<int, int> minMax = (Tuple<int, int>)obj;
            progressBar1.Maximum = minMax.Item1;
            progressBar1.Value = minMax.Item2;
        }, value);

        m_PreviousTime = now;
    }
}

  整个操作看起来要比Inovke复杂一点,与Invoke不一致的是SynchronizationContext无需对Control的援引,而Invoke必得先得有那些控件技能调用它的Invoke方法对它进行操作。

小结

  那篇博客内容有点长,不驾驭某些许人能够见到此间:)。最最先自己只是想写写WinFrom下异步调用Web
Service的片段东西,在生机勃勃始发那篇文书的标题是”异步编制程序在WinForm下的实践“,然则写着写着发掘更是多的迷团未有解开,其实都以部分老的技艺在此之前不曾接触和左右好,所以所幸就一遍性把他们都重新学习了壹遍,与大家享用。

  大家再来回看一下稿子所关联到的部分人命关天的概念:

  1. async/await
    在ASP.NET做的最大进献(开始时代ASP.NET的异步开拓形式雷同也会有与此相类似的进献卡塔尔,是在做客数据库的时候、访问远程IO的时候立刻放出了现阶段的管理性程,能够让这个线程回到线程池中,进而实现能够去管理任何诉求的效应。
  2. 异步的ASP.NET开辟能够在拍卖工夫上带给多大的增长,决意于大家的程序某个许时间是被封堵的,也正是那多个访谈数据库和远程Service的年月。
  3. 除此而外将代码改成异步,我们还亟需在IIS上做一些绝没错配置来兑现最优化。
  4. 无论是ASP.NET、WinForm依然Mobile、照旧平板,在巨型系统中都只是叁个与客商交互作用的端而已,所以无论你未来是做所谓的前端(JavaScript +
    CSS等),还是所谓的后端(ASP.NET MVC、WCF、Web API 等
    ),又也许是比较流行的移动端(IOS也好,Andrioid也罢,哪怕是不争气的WP卡塔尔,都只是成套大型系统中的零星大器晚成角而已。当然小编并不是降级那一个端的价值,正是因为大家注意于分歧,努力升高每叁个端的客商体验,能力让这么些大型系统有知名的机遇。笔者想说的是,在您对当今技术获得一定的成功之后,不要截止学习,因为整个软件架构类别中还会有众多过多名特别巨惠的事物值得我们去开采。
  5. APM和EAP是在async/await之前的两种分歧的异步编制程序情势。
  6. APM假如不打断主线程,那么成功公告(回调卡塔 尔(英语:State of Qatar)就能够实行在别的叁个线程中,从而给大家更新UI带给一定的标题。
  7. EAP的通知事件是在主线程中试行的,不会设有UI交互作用的主题材料。
  8. 最后,我们还学习了在Winform下不一致线程之间相互的标题,以至SynchronizationContext。
  9. APM是.NET下最先的异步编制程序方法,从.NET1.0的话就有了。在.NET2.0的时候,微软发掘到了APM的回调函数中与UI人机联作的难点,于是带给了新的EAP。APM与EAP平昔并存到.NET3.5,在.NET4.0的时候微软拉动了TPL,也正是大家所明白的Task编程,而.NET4.5就是大家大家领略的async/await了,可以看见.NET平昔在不停的迈入,加上多年来持续的和开源社区的搭档,跨平台等性子的引入,我们有理由相信.NET会越走越好。

  最终,那篇随笔从找质感学习到写出来,大致花了本身四个周未的大运,希望能够给急需的人也许感兴趣想要不断学习的人或多或少援救(不管是往前读书,依然以往学习卡塔尔国最终还要感激@田园里面包车型大巴蟋蟀,在阅读的时候给自家找了有个别错别字!

引用 & 增添阅读

http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx
http://blog.stevensanderson.com/2008/04/05/improve-scalability-in-aspnet-mvc-using-asynchronous-requests
http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx 
http://blogs.msdn.com/b/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx
http://mohamadhalabi.com/2014/05/08/thread-throttling-in-iis-hosted-wcf-sync-vs-async/
Pro Asynchronous Programs with .NET by Richard Blewett and Andrew Clymer

相关文章

admin

网站地图xml地图