异步编制程序

by admin on 2019年6月24日

概述

  在事先写的一篇关于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最终进入CL宝马X5实行拍卖的(刚毅建议不精通这一块的校友先看那篇小说,有助于你精通本小节),但是富有的步调都以依照三个线程的要是下开始展览的。IIS本人就是叁个八线程的劳作条件,要是大家从多线程的见地来看会产生怎么样变化吗?大家首先来看一下底下那张图。注意:大家下边包车型地铁步子是树立在IIS7.0今后的融会格局基础之上的。(注:下边那张图在dudu的唤起之后,重新做了有的寻觅专业,做了一部分改观,w3dt这一步来自于微博团组织对标题标反复查究,详细情况可以点这里

亚洲必赢手机入口 1

  我们再来梳理一下方面包车型大巴步骤:

  1. 富有的伸手最开头是由HTTP.SYS接收的,HTTP.SYS内部有三个体系维护着这几个须要,那些行列的request的多寡高出一定数额(私下认可是一千)的时候,HTTP.SYS就能间接再次来到503场馆(服务器忙),那是大家的首先个阀门。品质计数指标:“Http
    Service Request Queues\CurrentQueueSize
  2. 由w3dt负担把央浼从HTTP.SYS
    的连串中置放三个一见照旧端口的行列中,据非官方资料体现该队列长度为能为20(该队列是非公开的,未有文书档案,所以也从不品质计数器)。
  3. IIS
    的IO线程从上一步的队列中猎取乞求,如若是急需ASP.NET处理的,就能传送给CL库罗德线程池的Worker 线程,IIS的IO线程继续回来重新做该步骤。CL福特Explorer线程池的Worker线程数量是第二个阀门。
  4. 当CLEnclave中正在被管理的央浼数据越过一定值(最大并行处理央求数量,.NET4后头暗许是四千)的时候,从IO线程过来的呼吁就不会直接交给Worker线程,而是放到多少个进度池级其余一个连串了,等到这么些数据稍差于临界值的时候,才会把它再度提交Worker线程去管理。这是我们的第八个阀门。
  5. 上一步中谈到的丰盛进度池级其他队列有七个长短的界定,能够通过web.config里面包车型大巴processModel/requestQueueLimit来设置。那足以说也是三个阀门。当正在管理的数额超过所允许的最大并行管理央浼数量的时候,我们就能赢得503了。能够通过质量计数目的:“ASP.NET
    v4.0.30319\Requests Queued
    ” 来查阅该队列的尺寸。

 哪些因素会决定大家的响应本领

  从地点大家关系了几大阀门中,大家能够吸取上边包车型大巴多少个数字调整或许说影响着大家的响应工夫。

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

HTTP.SYS队列的尺寸

  以此笔者觉着没有供给特出解释,暗中认可值是一千。那个值取决于大家大家后边IIS
IO线程和Worker线程的管理速度,若是它们多个都管理不了,这些数字再大也未有用。因为最终他们会被贮存到进度池等第的队列中,所以只会导致内部存款和储蓄器的浪费。

最大Worker线程数量

  这么些值是足以在web.config中开展安排的。

亚洲必赢手机入口 2

  maxWorkerThreads: CL君越南中国实际管理央浼的最大Worker线程数量
  minWorkerThreads:CL路虎极光中实际管理必要的细小Worker线程数量

  minWorkerThreads的暗中认可值是1,合理的加大他们得以制止不须要的线程成立和销毁专业。

最大并行处理乞请数量

  进度池等第的队列给大家的CLRAV4一定的缓冲,那中间要专注的是,这一个行列还尚未进去到CLTiggo,所以它不会占领大家托管情形的别的国资本源,也正是把央求卡在了CLSportage的外部。我们须要在aspnet.config品级进行安插,大家能够在.net
fraemwork的安装目录下找到它。一般是 C:\Windows\Microsoft.NET\Framework\v4.0.30319
假让你安装的是4.0的话。

亚洲必赢手机入口 3

  maxConcurrentRequestPerCPU:
各样CPU所允许的最大并行管理诉求数量,当CLENCORE中worker线程正在管理的呼吁之和过量那些数时,从IO线程过来的伸手就能够被平放咱们进度池级其他体系中。
  maxConcurrentThreadsPerCPU: 设置为0即禁用。
  requestQueue: 进度池等级队列所允许的长度  

async和await 做了哪些?

  大家好不轻易要切入大旨了,拿ASP.NET
MVC比方,假如不使用async的Action,那么必然,它是在贰个Woker线程中施行的。当大家访问片段web
service,也许读文件的时候,那一个Worker线程就能够被卡住。若是大家以此Action实践时间一同是100ms,其余访问web
service花了80ms,理想图景下一个Worker线程一秒能够响应十三个央浼,假如我们的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大家起码节省了1四千ms的光阴,那十八个worker线程又会再去管理诉求,尽管如约每一个央求100ms的拍卖时间大家还足以再充实1五拾柒个诉求。而且别忘了100ms是基于共同境况下,包蕴等待时间在内的底蕴上赢得的,所以其实际景况况也许还要多,当然大家这里未有算上线程切换的时间,所以实际上处境中是有好几出入的,可是应该不会比非常的大,因为大家的线程都以依附线程池的操作。
  全数结果是24个Worker线程不选取异步的图景下,1s能自理200个伏乞,而使用异步的情状下得以管理3五拾七个需要,立马进步70%呀!选用异步之后,对于同样的乞请数量,要求的Worker线程数据会大大减弱二分一左右,三个线程至少会在堆上分配1M的内部存款和储蓄器,即使是一千个线程那便是1G的容积,纵然内部存款和储蓄器未来有利于,可是省着终归是好的呗,而且越来越少的线程是足以减去线程池在维护线程时发出的CPU消耗的。另:dudu分享 CLCRUISER1秒之内只好成立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线程。恐怕在部分Mini的系统中WinForm非常的少提到到多线程,因为WinForm本身的优势就在它是独自运行在客户端的,在质量上和操作性上都会有相当的大的优势。所以众多中型小型型的WinForm系统都是一贯就走访数据库了,并且好多也唯有数量的传导,什么图片财富那是没有多少的,所以等待的时光是比很短的,基本不用费怎么样脑子去思量如何3秒之内必须将页面彰显到用户前面这种难点。

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

  咱们地点说的是中型Mini型的WinForm,假使是大型的种类啊?如若WinForm只是别的的非常的小片段,就如大家作品初叶说的还应该有大多别的众四个手提式有线电话机客户端,Web客户端,平板客户端呢?假使客户端好多形成数据库撑不住如何做?
想在个中加一层缓存如何做?

  拿二个b2b的网址成效比如,用户可以因而网址下单,手机也能够下单,仍是能够通过Computer的桌面客户端下单。在下完单之后要成功交易,库存扣减,发送订单确认布告等等作用,而任由您的订单是由此哪些端达成的,那几个效应我们都要去做,对啊?那我们就不可能独立放在WinForm里面了,不然这么些代码在别的的端里面又得整体斩新再逐条完毕,同样的代码放在分裂的地点那不过非常惊险的,所以就有了我们后来的SOA架构,把这一个效应都分红服务,每种类型的端都以调用服务就足以了。一是足以统一保养那一个效能,二是能够很有益的做扩充,去越来越好的适应作用和架构上的恢弘。比方说像上边那样的多个种类。

 亚洲必赢手机入口 4

  在上海体育场合中,Web端即便也是属于大家日常说的服务端(以致是由多台服务器组成的web会集),但是对大家任何系统的话,它也只是贰个端而已。对于二个端的话,它自个儿只管理和用户交互的主题材料,其他全数的功用,业务都会付给后来台管理。在大家地方的架构中,应用层都不会间接到位真正业务逻辑相关的管理,而是放到我们更下层数据层去做拍卖。那么应用层首要援救做一些与用户交互的一些效益,若是手提式有线话机短信发送,邮件发送等等,并且能够依靠优先级接纳是放入队列中稍候管理或然直接调用成效服务及时处理。

  在这么的三个连串中,大家的Web服务器能够,Winform端也好都将只是整个系统中的三个终极,它们首要的其余是用户和前边服务时期的贰个桥梁。涉及到Service的调用之后,为了给用户能够的用户体验,在WinForm端,大家自然将要考虑异步的标题。 

WinForm异步调用Web 瑟维斯

  有了像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
Service的。

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到伍仟000的平方全体加起来,看起来是贰个百般耗费时间的操作,于是我们用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假若不封堵主线程,那么成功布告(回调)就能实行在别的贰个线程中,从而给我们更新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

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图