必赢体育现在还应该有人写WinForm吗

作者:必赢网站

概述

  在事先写的风度翩翩篇有关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响应技巧
    • 并行处理的步调
    • 哪些因素影响了大家的响应才能
    • async 和 await做了哪些?
    • 几点建议
  • 早期Web 瑟维斯的异步形式APM
    • 当WinForm遇到Web Service
    • WinForm异步调用Web Service
  • APM异步编制程序详解
    • 线程难题
    • 从Delegate开始
    • 重复认知APM
  • EAP(Event-Based Asynchroronous Pattern)
    • 线程难点
  • async/await 给WinForm编制程序带来了什么?
  • 不等线程之间通信的难点
    • 万能的InvokeI
    • SynchronizationContex上下文同步对象
  • 小结
  • 引用 & 扩张阅读

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哈弗举行拍卖的(生硬建议不驾驭那风流洒脱块的同窗先看那篇小说,有利于你精晓本小节),不过全数的步子都以基于三个线程的只要下举办的。IIS自己正是贰个多线程的做事境遇,假诺大家从二十四线程的观点来看会发生怎么着变化呢?大家率先来看一下上边那张图。注意:大家上面包车型客车手续是树立在IIS7.0现在的三合一情势基础之上的。(注:上边那张图在dudu的提醒之后,重新做了风度翩翩部分查找专门的工作,做了一些改成,w3dt这一步来自于新浪团队对难题的不停探求,详细的情况能够点这里)

必赢体育 1

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

  1. 具备的伸手最最初是由HTTP.SYS接受的,HTTP.SYS内部有贰个连串维护着那么些须求,那么些行列的request的多寡超过一定数额(私下认可是一千)的时候,HTTP.SYS就能一贯回到503情景(服务器忙),那是大家的第一个阀门。质量计数指标:“Http Service Request QueuesCurrentQueueSize
  2. 由w3dt担负把必要从HTTP.SYS 的行列中放到贰个对应端口的类别中,据非官方资料突显该队列长度为能为20(该队列是非公开的,未有文书档案,所以也远非质量计数器)。
  3. IIS 的IO线程从上一步的行列中获得央求,假使是内需ASP.NET管理的,就能够传递给CL讴歌MDX线程池的Worker 线程,IIS的IO线程继续回到重新做该步骤。CL福特Explorer线程池的Worker线程数量是第贰个阀门。
  4. 当CLEnclave中正在被拍卖的伸手数据超过一定值(最大并行管理必要数量,.NET4自此默许是陆仟)的时候,从IO线程过来的倡议就不会平昔提交Worker线程,而是放到二个进度池级其他叁个种类了,等到那些数量低于临界值的时候,才会把它再度提交Worker线程去管理。那是我们的第八个阀门。
  5. 上一步中聊到的不行进度池品级的行列有二个尺寸的范围,能够经过web.config里面包车型地铁processModel/requestQueueLimit来安装。那能够说也是三个阀门。当正在管理的数码超越所允许的最大并行管理诉求数量的时候,大家就能博得503了。能够通过品质计数指标:“ASP.NET v4.0.30319Requests Queued” 来查看该队列的尺寸。

 哪些因素会垄断大家的响应技巧

  从地点大家关系了几大阀门中,大家得以摄取上面的多少个数字调控也许说影响着大家的响应工夫。

  1. HTTP.SYS队列的长短
  2. CL福睿斯线程池最大Worker线程数量
  3. 最大并行管理央浼数量
  4. 进度池品级队列所允许的长短

HTTP.SYS队列的长短

  其风流倜傥自家感觉无需拾分解释,暗中同意值是1000。这几个值决议于我们我们前边IIS IO线程和Worker线程的管理速度,若是它们三个都处理不了,这一个数字再大也尚无用。因为最终他们会被积存到进度池级其余队列中,所以只会形成内部存款和储蓄器的浪费。

最大Worker线程数量

  那么些值是能够在web.config中打开安顿的。

必赢体育 2

  maxWorkerThreads: CLQashqai中实际管理哀告的最大Worker线程数量
  minWorkerThreads:CLOdyssey中真实管理须要的小小Worker线程数量

  minWorkerThreads的暗中认可值是1,合理的加大他们得以制止不供给的线程创设和销毁工作。

最大并行管理央求数量

  进度池品级的队列给大家的CL奥迪Q7一定的缓冲,这里面要在意的是,这些行列还尚无进去到CLLacrosse,所以它不会据有大家托管蒙受的别的财富,相当于把必要卡在了CLLAND的外部。大家必要在aspnet.config等第实行配备,大家得以在.net fraemwork的设置目录下找到它。经常是 C:WindowsMicrosoft.NETFrameworkv4.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线程旭日初升秒能够响应12个乞请,要是大家的maxWorkerThreads是10,那大家新闯事物正在生机勃勃秒内连接可响应诉求便是100。假诺说大家想把这些可响应乞求数升到200咋办吧?

  有人会说,那还不简单,把maxWorkerThreads调20不就行了么? 其实我们做也未尝怎么 难题,确实是足以的,而且也的确能起到效果与利益。那大家为啥还要搜索枯肠的搞哪样 async/await呢?搞得脑子都晕了?async/await给大家消除了何等难点?它可以在我们会见web service的时候把当前的worker线程放走,将它放回线程池,那样它就足以去管理别的的央浼了。等到web service给我们再次回到结果了,会再到线程池中自由拿四个新的woker线程继续往下进行。也即是说大家降低了那部分等候的年月,充份利用了线程。

    我们来对待一下使用async/awit和不行使的事态,

  不利用async/await: 贰13个woker线程1s得以拍卖200个乞求。

  那转变到总的时间的就是 20 * 1000ms =  20000ms,
  此中等待的小运为 200 * 80ms = 16000ms。
  也正是说使用async/await我们足足节约了16000ms的时日,那18个worker线程又会再去管理伏乞,纵然根据种种哀告100ms的管理时间大家还是能够再追加1六12个诉求。而且别忘了100ms是依靠共同意况下,包含等待时间在内的根底上获得的,所以真实景况恐怕还要多,当然我们那边没有算上线程切换的日子,所以实际景况中是有点差其余,可是应该不会极大,因为大家的线程都以基于线程池的操作。
  全体结果是二十一个Worker线程不应用异步的图景下,1s能自理200个央浼,而选用异步的意况下可以拍卖3伍17个要求,立马提高十分八呀!选用异步之后,对于同如日方升的央求数量,必要的Worker线程数据会大大收缩百分之五十左右,二个线程起码会在堆上分配1M的内部存款和储蓄器,即便是一千个线程那就是1G的容积,即使内部存款和储蓄器未来方便,不过省着到底是好的呗,何况越来越少的线程是足以缩小线程池在爱抚线程时产生的CPU消耗的。另:dudu分享 CLMurano1秒之内只可以创立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在性能上有这么大的优势,那它还索要异步吗?

  大家地方说的是中型Mini型的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异步调用Web瑟维斯"那结中用到的法子,调完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中相遇的题材同样,偶然候大家需求在三个线程中传递一些数码可能做一些操作到另三个线程。不过在超越59%意况下那是不允许的,出于安全因素的设想,每二个线程都有它独自的内部存储器空间和上下文。因而在.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开辟能够在管理技艺上带来多大的增高,决定于我们的程序有稍许时间是被打断的,也等于那么些访谈数据库和长途瑟维斯的小时。
  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会越走越好。

  最终,这篇文章从找材料学习到写出来,大概花了笔者三个周未的时刻,希望能够给急需的人要么感兴趣想要不断学习的人一点增加援救(不管是往前读书,依旧以往学习)最终还要感激@田园里面包车型客车蟋蟀,在翻阅的时候给本人找了部分错别字!

援引 & 扩充阅读



 


Pro Asynchronous Programs with .NET by Richard Blewett and Andrew Clymer

本文由必赢体育发布,转载请注明来源

关键词: