当前位置: 首页 > news >正文

加强文化网站建设屏边县住房和城乡建设局网站

加强文化网站建设,屏边县住房和城乡建设局网站,帮人做微信是哪个网站,二维码生成器加logo在之前写的一篇关于async和await的前世今生的文章之后#xff0c;大家似乎在async和await提高网站处理能力方面还有一些疑问#xff0c;很多网站本身也做了不少的尝试。今天我们再来回答一下这个问题#xff0c;同时我会做一个async和await在WinForm中的尝试#xff0c;并且…在之前写的一篇关于async和await的前世今生的文章之后大家似乎在async和await提高网站处理能力方面还有一些疑问很多网站本身也做了不少的尝试。今天我们再来回答一下这个问题同时我会做一个async和await在WinForm中的尝试并且对比在4.5之前的异步编程模式APM/EAP和async/await的区别最后我还会探讨在不同线程之间交互的问题。 众所周知IIS存在着处理能力的问题但是WinForm却是UI响应的问题并且WinForm的UI线程至始至终都是同一个所以两者之间有一定的区别。    有人可能会问现在还有人写WinForm吗当然有啊比如说我还在用但它确实是一个比较老的东西呢不如WPF酷炫技术也不如WPF先进。 但是从架构层面来讲不管是Web还是WinForm又或是WPFMobile这些都只是表现层你觉得不是吗 现在的大型系统一般桌面客户端、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最后进入CLR进行处理的强烈建议不了解这一块的同学先看这篇文章有助于你理解本小节但是所有的步骤都是基于一个线程的假设下进行的。IIS本身就是一个多线程的工作环境如果我们从多线程的视角来看会发生什么变化呢首先我们看下面这张图注意下面的步骤是建立在IIS 7.0以后的集成模式基础之上的。 我们再来梳理一下上面的步骤 所有的请求最开始是由HTTP.SYS接收的HTTP.SYS内部有一个队列维护着这些请求这个队列的request的数量大于一定数量默认是1000的时候HTTP.SYS就会直接返回503状态服务器忙这是我们的第一个阀门。性能计数指标“Http Service Request Queues\CurrentQueueSize”。 由w3dt负责把请求从HTTP.SYS 的队列中放到一个对应端口的队列中据非官方资料显示该队列长度能为20该队列是非公开的没有文档所以也没有性能计数器。 IIS 的IO线程从上一步的队列中获取请求如果是需要ASP.NET处理的就会转交给CLR 线程池的Worker 线程IIS的IO线程继续返回重复做该步骤。CLR 线程池的Worker线程数量是第二个阀门。 当CLR中正在被处理的请求数据大于一定值最大并行处理请求数量.NET4以后默认是5000的时候从IO线程过来的请求就不会直接交给Worker线程而是放到一个进程池级别的一个队列了等到这个数量小于临界值的时候才会把它再次交给Worker线程去处理。这是我们的第三个阀门。 上一步中说到的那个进程池级别的队列有一个长度的限制可以通过web.config里面的processModel/requestQueueLimit来设置。这可以说也是一个阀门。当正在处理的数量大于所允许的最大并行处理请求数量的时候我们就会得到503了。可以通过性能计数指标“ASP.NET v4.0.30319\Requests Queued” 来查看该队列的长度。 哪些因素会控制我们的响应能力 从上面我们提到了几大阀门中可以得出下面的几个数字控制或者说影响着我们的响应能力。    HTTP.SYS队列的长度 CLR线程池最大Worker线程数量 最大并行处理请求数量 进程池级别队列所允许的长度 HTTP.SYS队列的长度 这个我觉得不需要特别解释默认值是1000。这个值取决于我们我们后面IIS IO线程和Worker线程的处理速度如果它们两个都处理不了这个数字再大也没有用。因为最后他们会被存储到进程池级别的队列中所以只会造成内存的浪费。 最大Worker线程数量   这个值是可以在web.config中进行配置的。 maxWorkerThreads: CLR中真实处理请求的最大Worker线程数量。   minWorkerThreads:CLR中真实处理请求的最小Worker线程数量。   minWorkerThreads的默认值是1合理的加大它们可以避免不必要的线程创建和销毁工作。 最大并行处理请求数量  进程池级别的队列给CLR一定的缓冲需要注意这个队列还没有进入到CLR所以它不会占用我们托管环境的任何资源把请求卡在CLR的外面。我们需要在aspnet.config级别进行配置在.Net Fraemwork的安装目录下找到它。一般是 C:\Windows\Microsoft.NET\Framework\v4.0.30319 如果你安装的是4.0版本。 maxConcurrentRequestPerCPU: 每个CPU所允许的最大并行处理请求数量当CLR中Worker线程正在处理的请求之和大于这个数时从IO线程过来的请求就会被放到我们进程池级别的队列中。   maxConcurrentThreadsPerCPU: 设置为0即禁用。   requestQueue: 进程池级别队列所允许的长度。    async和await 做了什么 终于要切入主题了就ASP.NET MVC举例如果不采用async的Action那么毫无疑问它是在一个Woker线程中执行的。当我们访问一些web service或者读文件的时候这个Worker线程就会被阻塞。假设我们这个Action执行时间一共是100ms其它访问web service花费80ms理想情况下一个Worker线程一秒可以响应10个请求假设我们的maxWorkerThreads是10那我们一秒内总是可响应请求就是100。如果说我们想把这个可响应请求数升到200怎么做呢      有人会说这还不简单把maxWorkerThreads调20不就行了么 其实这么做也没有什么问题确实是可以的而且也确实能起到作用。那我们为什么还要大费周章的搞什么 async/await呢搞得脑子都晕了async/await给我们解决了什么问题它可以在我们访问web service的时候把当前的Worker线程放走将它放回线程池这样它就可以去处理其它的请求了。等到web service给我们返回结果了会再到线程池中随机拿一个新的woker线程继续往下执行。也就是说我们减少了那一部分等待的时间充份利用了线程。      我们来对比一下使用async/awit和不使用的情况   不使用async/await 20个woker线程1s可以处理200个请求。   那转换成总的时间的就是 20 * 1000ms 20000ms   其中等待的时间为 200 * 80ms 16000ms。   也就是说使用async/await我们至少节约了16000ms的时间这20个Worker线程又会再去处理请求即使按照每个请求100ms的处理时间我们还可以再增加160个请求。而且别忘了100ms是基于同步情况下包括等待时间在内的基础上得到的所以实际情况可能还要多当然这里没有算上线程切换的时间所以实际情况中是有一点差异的但是应该不会很大因为我们的线程都是基于线程池的操作。      所有结果是20个Worker线程不使用异步的情况下1s能自理200个请求而使用异步的情况下可以处理360个请求立刻提升80%采用异步之后对于同样的请求数量需要的Worker线程数据会大大减少50%左右一个线程至少会在堆上分配1M的内存如果是1000个线程那就是1G的容量虽然内存现在便宜但是省着总归是好的嘛而且更少的线程是可以减少线程池在维护线程时产生的CPU消耗的。另CLR在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下实现的。 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线程与Android系统很类似。也许在一些小型的系统中WinForm很少涉及到多线程因为WinForm本身的优势就在它是独立运行在客户端在性能上和可操作性上都会有很大的优势。所以很多中小型的WinForm系统都是直接就访问数据库了并且基本上也只有数据的传输什么图片资源那是很少的所以等待的时间是很短的基本不用考虑像在3秒之内必须将页面显示到用户面前这种问题。      既然WinForm在性能上有这么大的优势那它还需要异步吗      我们上面说的是中小型WinForm如果是大型的系统呢如果WinForm只是其它的很小一部分就像我们文章开始说的还有很多其它成千上万个手机客户端Web客户端平板客户端呢如果客户端很多导致数据库撑不住怎么办 想在中间加一层缓存怎么办      比如B2B的网站功能用户可以通过网站下单手机也可以下单还可以通过电脑的桌面客户端下单。在下完单之后要完成交易库存扣减发送订单确认通知等功能而不管你的订单是通过哪个端完成的这些功能我们都要去做对吗那我们就不能单独放在WinForm里面不然这些代码在其它的端里面又得全部全新再一一实现同样的代码放在不同的地方那可是相当危险的所以就有了我们后来的SOA架构把这些功能都抽成服务每种类型的端都是调用服务就可以了。一是可以统一维护这些功能二是可以很方便的做扩展去更好的适应功能和架构上的扩展。比如像下面这样的一个系统。 在上图中Web端虽然也是属于我们平常说的服务端甚至是由多台服务器组成的web群集但是对我们整个系统来说它也只是一个端而已。对于一个端来说它本身只处理和用户交互的问题其余所有的功能业务都会交给后来台处理。在上面的架构中应用层都不会直接参加真正业务逻辑相关的处理而是放到我们更下层数据层去做处理。那么应用层主要协助做一些与用户交互的一些功能如果手机短信发送邮件发送等等并且可以根据优先级选择是放入队列中稍候处理还是直接调用功能服务立即处理。 在这样的一个系统中我们的Web服务器也好Winform端也好都将只是整个系统中的一个终端它们主要的作用是用户和后面服务之间的一个桥梁。涉及到Service的调用之后为了给用户良好的体验在WinForm端我们自然就要考虑异步的问题。    WinForm异步调用Web Service 有了像VS这样强大的工具为我们生成代理类我们在写调用Web service的代码时就可以像调用本地类库一样调用Web Service了我们只需要添加一个Web Reference就可以了。 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? NODesktop4.0.vshost.exe Information: 0 : Is current thread from thread pool? NODesktop4.0.vshost.exe Information: 0 : Start calling web service on thread: 9Desktop4.0.vshost.exe Information: 0 : Is current thread a background thread? YESDesktop4.0.vshost.exe Information: 0 : Is current thread from thread pool? YESDesktop4.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: 10Desktop4.0.vshost.exe Information: 0 : I am eating.... on thread: 6Desktop4.0.vshost.exe Information: 0 : I am done eating.... on thread: 6clean是我们传进去的callback该方法会在我们的eat方法执行完之后被调用所以它会和我们eat方法在同一个线程中被调用。大家如果熟悉代理的话就会知道代码实际上会被编译成一个类而BeginInvoke和EndInvoke方法正是编译器为我们自动加进去的方法我们不用额外做任何事情这在早期没有TPL和async/await之前APM从.NET1.0时代就有了的确是一个不错的选择。 再次认识APM 了解了Delegate实现的BeginInvoke和EndInvoke之后我们再来分析一下APM用到的那些对象。 拿我们Web service的代理类来举例它为我们生成了以下3个方法 string DownloadContent(string url) 同步方法 IAsyncResult BeginDownloadContent(string url, AsyncCallback callback, object asyncState) 异步开始方法 EndDownloadContent(IAsyncResult asyncResult)异步结束方法在我们调用EndDownloadContent方法的时候如果我们的web service调用还没有返回那这个时候就会用阻塞的方式去拿结果。但是在我们传到BeginDownloadContent中的callback被调用的时候那操作一定是已经完成了也就是说IAsyncResult.IsCompleted true。而在APM异步编程模式中Begin方法总是返回IAsyncResult这个接口的实现。IAsyncReuslt仅仅包含以下4个属性 WaitHanlde通常作为同步对象的基类并且可以利用它来阻塞线程更多信息可以参考MSDN 。 借助于IAsyncResult的帮助我们就可以通过以下几种方式去获取当前所执行操作的结果。 轮询 强制等待 完成通知   完成通知就是在WinForm异步调用WebService那段中用到的方法调用完Begin方法之后主线程就算完成任务了。我们也不用监控该操作的执行情况当该操作执行完之后我们在Begin方法中传进去的callback就会被调用了我们可以在那个方法中调用End方法去获取结果。下面我们再简单说一下前面两种方式。 //轮询获取结果代码 ar 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成为了你唯一的选择。我没有尝试过手动生成代理类有兴趣的同学可以尝试一下让我们来看一下在.NET 4.0中我们是如何异步调用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: 10Desktop4.vshost.exe Information: 0 : Is current from thread pool? : NODesktop4.vshost.exe Information: 0 : Completed DownloadContentAsync on thread: 10Desktop4.vshost.exe Information: 0 : Is current from thread pool? : NOasync/await 给WinFrom带来了什么 如果说async给ASP.NET带来的是处理能力的提高那么在WinForm中给程序员带来的好处则是最大的。我们再也不用因为要实现异步写回调或者绑定事件了省事了可读性也提高了。不信你看下面我们将调用我们那个web service的代码在.NET 4.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 Taskdouble.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运行吧 当执行到这里的时候程序就崩溃了告诉我们”无效操作只能从创建porgressBar的线程访问它。“ 这也是我们一开始提到的在WinForm程序中只有UI主线程才能对UI进行操作其它的线程是没有权限的。接下来我们就来看看如果在WinForm中实现非UI线程对UI控制的更新操作。 不同线程之间通讯的问题 万能的Invoke WinForm中绝大多数的控件包括窗体在内都实现了Invoke方法可以传入一个Delegate这个Delegate将会被拥有那个控制的线程所调用从而避免了跨线程访问的问题。 Trace.TraceInformation(UI Thread : {0}, Thread.CurrentThread.ManagedThreadId); double sqrt await Taskdouble.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 : 9Desktop.vshost.exe Information: 0 : Run calculation on thread: 10Desktop.vshost.exe Information: 0 : Update UI on thread: 9Invoke方法比较简单我们就不做过多的研究了但是我们要考虑到一点Invoke是WinForm实现的UI跨线程沟通方式WPF用的却是Dispatcher如果是在ASP.NET下跨线程之间的同步又怎么办呢。为了兼容各种技术平台下跨线程同步的问题Microsoft在.NET 2.0的时候就引入了我们下面的这个对象。 SynchronizationContext上下文同步对象 为什么需要SynchronizationContext 就像我们在WinForm中遇到的问题一样有时候我们需要在一个线程中传递一些数据或者做一些操作到另一个线程。但是在绝大多数情况下这是不允许的出于安全因素的考虑每一个线程都有它独立的内存空间和上下文。因此在.NET 2.0微软推出了SynchronizationContext。      它主要的功能之一是为我们提供了一种将一些工作任务Delegate)以队列的方式存储在一个上下文对象中然后把这些上下文对象关联到具体的线程上当然有时候多个线程也可以关联到同一个SynchronizationContext对象。获取当前线程的同步上下文对象可以使用SynchronizationContext.Current。同时它还为我们提供以下两个方法Post和Send分别是以异步和同步的方法将我们上面说的工作任务放到我们SynchronizationContext的队列中。    SynchronizationContext示例 还是拿我们上面Invoke中用到的例子举例只是这次我们不直接调用控件的Invoke方法去更新它而是写了一个Report的方法专门去更新UI。 double sqrt await Taskdouble.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 Tupleint, 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(Tupleint, int value) {DateTime now DateTime.Now;if ((now - m_PreviousTime).Milliseconds 100){m_SynchronizationContext.Post((obj) {Tupleint, int minMax (Tupleint, int)obj;progressBar1.Maximum minMax.Item1;progressBar1.Value minMax.Item2;}, value);m_PreviousTime now;} } 整个操作看起来要比Inovke复杂一点与Invoke不同的是SynchronizationContext不需要对Control的引用而Invoke必须先得有那个控件才能调用它的Invoke方法对它进行操作。 小结 这篇博客内容有点长不知道有多少人可以看到这里。最开始我只是想写写WinFrom下异步调用Web Service的一些东西在一开始这篇文件的题目是”异步编程在WinForm下的实践“但是写着写着发现越来越多的迷团没有解开其实都是一些老的技术以前没有接触和掌握好所以所幸就一次性把他们都重新学习了一遍与大家分享。      我们再来回顾一下文章所涉及到的一些重要的概念    async/await 在ASP.NET做的最大贡献早期ASP.NET的异步开发模式同样也有这样的贡献是在访问数据库的时候、访问远程IO的时候及时释放了当前的处理进程可以让这些线程回到线程池中从而实现可以去处理其它请求的功能。 异步的ASP.NET开发能够在处理能力上带来多大的提高取决于我们的程序有多少时间是被阻塞的也就是那些访问数据库和远程Service的时间。 除了将代码改成异步我们还需要在IIS上做一些相对的配置来实现最优化。 不管是ASP.NET、WinForm还是Mobile、还是平板在大型系统中都只是一个与用户交互的端而已所以不管你现在是做所谓的前端JavaScript CSS等)还是所谓的后端(ASP.NET MVC、WCF、Web API 等 )又或者是移动端IOS也好Andrioid也罢哪怕是不争气的WP都只是整个大型系统中的零星一角而已。当然我并不是贬低这些端的价值正是因为我们专注于不同努力提高每一个端的用户体验才能让这些大型系统有露脸的机会。我想说的是在你对现在的技术取得一定的成就之后不要停止学习因为整个软件架构体系中还有很多很多美妙的东西值得我们去发现。 APM和EAP是在async/await之前的两种不同的异步编程模式。 APM如果不阻塞主线程那么完成通知回调就会执行在另外一个线程中从而给我们更新UI带来一定的问题。 EAP的通知事件是在主线程中执行的不会存在UI交互的问题。 最后我们还学习了在Winform下不同线程之间交互的问题以及SynchronizationContext。 APM是.NET下最早的异步编程方法从.NET 1.0以来就有了。在.NET 2.0的时候微软意识到了APM的回调函数中与UI交互的问题于是带来了新的EAP。APM与EAP一直共存到.NET 3.5在.NET 4.0的时候微软带来了TPL也就是我们所熟知的Task编程而.NET 4.5就是我们大家知道的async/await了可以看到.NET一直在不停的进步加上最近不断的和开源社区的合作跨平台等特性的引入我们有理由相信.NET会越走越好。   最后这篇文章从找资料学习到写出来差不多花了我两个周未的时间希望能够给需要的人或者感兴趣想要不断学习的人一点帮助不管是往前学习还是往后学习。
http://www.w-s-a.com/news/843587/

相关文章:

  • 网站备案号怎么查楼书设计素材网站
  • 网站设计机构有哪些中国建设银行网站登录不上
  • 烟台理工学校网站罗湖建设网站
  • 卑鄙的网站开发公司郑州人才网站
  • 成都专业的网站设计公司文化建设的成就
  • 做书籍封皮的网站如何建网站教程视频
  • 唐山建站公司模板ipfs做网站
  • 贵阳做网站品牌网站模板
  • 紫网站建设我的个人博客
  • 优秀网站菜单网页上的视频怎么下载
  • 龙口建网站公司价格国内的平面设计网站
  • 电子商务网站建设与管理读后感上海市基础工程公司
  • 织梦免费企业网站做网站时,404网页如何指向
  • 摄影工作室网站源码百度为什么会k网站
  • 哪个网站有淘宝做图的素材网站分享做描点链接
  • 做哪个网站零售最好网站空间在哪里
  • 荆州网站建设多少钱南阳做网站推广
  • 网站代理打开个人网站设计源码
  • 做php网站的话要学什么语言wordpress搜索不到
  • 金华官方网站建设网络营销策划模板
  • 网站开发到上线在线生成小程序
  • 动易网站设计方案郑州营销网站建设
  • 怎么上网站做简易注销的步骤郑州大学现代远程教育《网页设计与网站建设》课程考核要求
  • 新乡网站建设新乡长沙本地论坛有哪些
  • 潍坊中企动力做的网站怎么样wordpress接入微博
  • 网站开发者所有权归属网站项目建设的必要性
  • 菜鸟网站编程广州网站设计权威乐云践新
  • 网站做接口到app 价格大地资源免费视频观看
  • 怎么给钓鱼网站做防红网站建设相关的
  • 教育培训的网站建设湖南网站建设小公司