深圳建站公司兴田德润电话多少,北京品牌网站设计,怎么做一家网站,自己能注册网站吗如果说async给ASP.NET带来的是处理能力的提高#xff0c;那么在WinForm中给程序员带来的好处则是最大的。我们再也不用因为要实现异步写回调或者绑定事件了#xff0c;省事了#xff0c;可读性也提高了。不信你看下面我们将调用我们那个web service的代码在.NET4.5下实现一下… 如果说async给ASP.NET带来的是处理能力的提高那么在WinForm中给程序员带来的好处则是最大的。我们再也不用因为要实现异步写回调或者绑定事件了省事了可读性也提高了。不信你看下面我们将调用我们那个web service的代码在.NET4.5下实现一下1234567private 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后面的代码执行在另外一个线程中会发生什么事情呢1234567891011121314151617181920212223private 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运行吧 Bomb~ 当执行到这里的时候程序就崩溃了告诉我们”无效操作只能从创建porgressBar的线程访问它。“ 这也是我们一开始提到的在WinForm程序中只有UI主线程才能对UI进行操作其它的线程是没有权限的。接下来我们就来看看如果在WinForm中实现非UI线程对UI控制的更新操作。 万能的Invoke WinForm中绝大多数的控件包括窗体在内都实现了Invoke方法可以传入一个Delegate这个Delegate将会被拥有那个控制的线程所调用从而避免了跨线程访问的问题。12345678910111213141516Trace.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 : 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。123456789101112double 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方法了。12345678910111213141516171819202122232425private 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方法对它进行操作。