今昔还恐怕有人写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管理工科夫

  首先响应本事并不完全部都以说咱俩前后相继质量的标题,一时候恐怕你的前后相继还没此外难题,并且细心经过优化,可是响应手艺也许未有上来,网址品质分析是三个犬牙相错的活,有时候只可以靠经历和相连的品尝本领达到比较好的功效。当然大家前天商酌的重视是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最终踏向CLXC90实行拍卖的(刚烈提议不通晓这一块的同桌先看那篇作品,有利于你精通本小节卡塔尔国,不过全体的手续都以基于一个线程的只要下展开的。IIS自个儿便是三个三十四线程的工作情况,假使大家从八线程的思想来看会产生哪些变化吧?大家第一来看一下底下那张图。注意:我们下边的步骤是起家在IIS7.0现在的合併情势功底之上的。(注:上面那张图在dudu的提示之后,重新做了有的搜索工作,做了大器晚成都部队分改造,w3dt这一步来自于新浪集体对题指标一再搜求,详细的情况能够点这里

澳门黄冠娱乐备用网址 1

  我们再来梳理一下方面的步骤:

  1. 具有的央求最早叶是由HTTP.SYS选择的,HTTP.SYS内部有一个队列维护着那几个央求,这些队列的request的数码抢先一定数额(默许是1000卡塔尔国的时候,HTTP.SYS就能直接回到503情景(服务器忙卡塔 尔(英语:State of Qatar),那是我们的第三个阀门。质量计数指标:“Http
    Service Request Queues\CurrentQueueSize
  2. 由w3dt担当把央浼从HTTP.SYS
    的连串中贮存三个相应端口的体系中,据非官方资料显示该队列长度为能为20(该队列是非公开的,未有文书档案,所以也并未有质量流速计卡塔尔。
  3. IIS
    的IO线程从上一步的队列中收获央求,若是是亟需ASP.NET管理的,就能够传送给CL卡宴线程池的Worker 线程,IIS的IO线程继续回来重新做该手续。CLLacrosse线程池的Worker线程数量是第二个阀门。
  4. 当CL奥迪Q5中正在被拍卖的哀求数据超越一定值(最大并行管理诉求数量,.NET4今后默许是5000卡塔 尔(阿拉伯语:قطر‎的时候,从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队列的长短

  这一个本身认为不须求至极解释,暗中认可值是1000。这么些值决定于大家大家前边IIS
IO线程和Worker线程的处理速度,若是它们八个都管理不了,这些数字再大也并未有用。因为最后他们会被寄存到进程池等级的种类中,所以只会引致内部存款和储蓄器的浪费。

最大Worker线程数量

  那个值是足以在web.config中举行铺排的。

澳门黄冠娱乐备用网址 2

  maxWorkerThreads: CLRAV4中真正管理央浼的最大Worker线程数量
  minWorkerThreads:CLRAV4中真实管理诉求的渺小Worker线程数量

  minWorkerThreads的暗中认可值是1,合理的加大他们能够避免无需的线程创建和销毁职业。

最大并行管理乞请数量

  进程池级其余队列给大家的CL奔驰M级一定的缓冲,那其间要专心的是,那些行列还并未步入到CLENCORE,所以它不会占领我们托管情形的其它国资本源,也正是把央求卡在了CL福睿斯的外围。我们供给在aspnet.config等第进行布署,大家能够在.net
fraemwork的安装目录下找到它。常常是 C:\Windows\Microsoft.NET\Framework\v4.0.30319
假诺您安装的是4.0的话。

澳门黄冠娱乐备用网址 3

  maxConcurrentRequestPerCPU:
各个CPU所允许的最大并行管理央求数量,当CLEscort中worker线程正在管理的伸手之和不只有那个数时,从IO线程过来的哀告就能够被放到大家进度池等第的队列中。
  maxConcurrentThreadsPerCPU: 设置为0即禁用。
  requestQueue: 进程池品级队列所允许的长短  

async和await 做了怎么着?

  我们毕竟要切入主旨了,拿ASP.NET
MVC举例,若是不采取async的Action,那么料定,它是在叁个Woker线程中施行的。当我们拜候一些web
service,或然读文件的时候,这些Worker线程就能够被封堵。假设大家那些Action试行时间一齐是100ms,此外访问web
service花了80ms,理想状态下四个Worker线程风姿洒脱秒能够响应13个伏乞,假若大家的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的岁月,那十八个worker线程又会再去管理央求,就算如约各种诉求100ms的拍卖时间大家还足以再追加1伍拾伍个诉求。並且别忘了100ms是依照协作景况下,富含等待时间在内的底子上拿到的,所以真实情状或者还要多,当然大家这里未有算上线程切换的时光,所以其实况况中是有点差距的,但是应当不会一点都不小,因为大家的线程都是基于线程池的操作。
  全部结果是21个Worker线程不选择异步的情景下,1s能自理200个要求,而利用异步之处下得以管理356个央求,立马进步百分之八十啊!采取异步之后,对于同生龙活虎的央浼数量,必要的Worker线程数据会大大减弱一半左右,三个线程起码会在堆上分配1M的内部存储器,若是是1000个线程那正是1G的容积,即便内存今后有扶助,但是省着究竟是好的嘛,况且越来越少的线程是足以收缩线程池在珍爱线程时发生的CPU消耗的。另:dudu分享 CL智跑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
瑟维斯。 大家那边所说的照准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
瑟维斯,那么Ajax(Asynchronous Javascript +
XML)就是大家客商端用到的异步编制程序本领。如若是任何的顾客端呢?比方说贰个CS的桌面程序?大家需求异步编制程序么?

当WinForm遇上Web Service

  WinForm不像托管在IIS的ASP.NET网址,会有多个线程池管理着多少个线程来拍卖客商的呼吁,换个说法ASP.NET网址生来正是基于八十多线程的。不过,在WinForm中,要是大家不特意使用八线程,那至始至终,都只有一个线程,称之为UI线程。或许在一些Mini的系统中WinForm超级少涉及到多线程,因为WinForm自己的优势就在它是单身运转在顾客端的,在性质上和可操作性上都会有极大的优势。所以广大中型小型型的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
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到5000000的平方全体加起来,看起来是三个卓殊耗费时间的操作,于是大家用Task.Run开了四个新的线程去实施。(注:借使是纯运算的操作,四线程操作对品质没有多大扶助,大家那边最主倘使想给UI二个进度突显当前行展到哪一步了。卡塔 尔(英语:State of Qatar)看起来没有怎么难点,大家按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

相关文章