好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ExecutionContext & SynchronizationContext

ExecutionContext & SynchronizationContext

最近在研究.net4.5中的有关异步编程的新特性,从自己Google Reader 订阅的一些博客中接触到了两个很陌生的单词ExecutionContext和SynchronizationContext,于是仔细研究了一下,记录下来备忘。
什么是ExecutionContext
在许多系统中thread-local storage(TLS)线程本地存储记录了正在运行的当前环境或者上下文的一些信息,而在CLR中ExecutionContext做了类似的事情.在同步的世界中,所有的一切都发生在当前线程内,线程内有关的所有数据对其内所有代码可见,也同时被所有代码所操纵影响.也就是说假设有方法ABC在当前线程内顺序执行,当前线程环境的一切信息对ABC都是可见的,同时ABC又影响着这些当前线程环境.但是在异步的世界情况变了,还假设有方法ABC,这三个方法有可能运行在不同的线程中,ABC三者是相互见不到对方线程信息的,所以需要在每个异步点传递当前线程环境信息到另一个线程中,另一个线程中的方法才能访问该线程中数据信息并且修改这些信息.完成这个任务就需要ExecutionContext记录当前线程环境然后再另一个线程中restore出来. 情况类似于这样:

 //   记录当前的环境信息到ec, 这些信息会在委托调用时通过静态的方法Run恢复出来 
ExecutionContext ec =  ExecutionContext.Capture(); 


ExecutionContext.Run(ec,   delegate   
{ 
…   //   在这的代码就能看见ec中的环境信息了。 
},  null );

在.Net FrameWork中所有处理异步情况的方法都会通过类似的方法Capture/Restore ExecutionContext(不包括unsafe代码),比如Task.Run,ThreadPool.QueueUserWorkItem,Delegate.BeginInvoke,Stream.BeginRead,DispatcherSynchronizationContext.Post 

比如Task.Run,当我们调用Run时,背后所做的事就是ExecutionContext.Capture()捕获当前线程环境,然后在Run中的delegate方法执行的时候把环境还原。

什么是SynchronizationContext

程序员都很热衷与抽象,对硬编码深恶痛绝,分层和抽象会为我们日后维护和扩展系统带来极大的便利,这也就是为什么会有接口,抽象类,和虚方法。而SynchronizationContext也是一种抽象。打个比方,当我们编写WinForm程序时,为避免后台处理海量数据带来的UI界面假死状态,通常会重开线程或者将这些工作放入线程池等,任务完成之后把处理的结果封送返回给UI线程时,通常会用Control.BeginInvoke方法。但是这种情况如果发生在WPF和Silverlight程序中呢,封送处理又得用Dispatcher.Run或者InvokeAsync.ASP.Net又是另一种情况。于是我们使用了不同了方法完成了相同的动作,那么对于不同的UI框架我们怎么处理这些相同事件呢?于是抽象的想法来了,这就是SynchronizationContext。它提供了一个虚方法Post(),这个方法会接收委托方法并且执行它。而对于WinForm的情况会提供WinFormSynchronizationContext,它会覆盖掉虚方法Post(),并且在子类中Post()调用Control.BeginInvoke;对于WPF或者Silverlight,会提供子类DispatcherSynchronizationContext,同样覆盖掉虚方法Post(),并且在子类Post中调用Dispatcher.Run。

 public   static   void   DoWork(Control c) 
{ 
ThreadPool.QueueUserWorkItem(  delegate   
    { 
..... c.BeginInvoke( delegate { .../对UI的操作 }); }); } 如果替换成SynchronizationContext去写就成了这样: public static void DoWork(SynchronizationContext sc) { ThreadPool.QueueUserWorkItem( delegate { … // do work on ThreadPool sc.Post( delegate { … // do work on UI }, null ); }); }
或者如下 public static void DoWork() { var sc = SynchronizationContext.Current; ThreadPool.QueueUserWorkItem( delegate { … // do work on ThreadPool sc.Post( delegate { … // do work on the original context }, null ); }); }

ExecutionContext VS SynchronizationContext

对比两者你会发现它们都会在异步操作时捕获当前线程环境上下文,但后续操作不一样,ExecutionContext会调用delegate方法并在执行时在另一个线程中恢复该线程环境状态。而SynchronizationContext仅仅是用当前捕获的环境信息去调用委托方法,这个委托方法怎么什么时候执行,在哪执行,怎么执行都取决于底层的具体实现。

注意:

 以下CodeProject文章中有一点讲得不太准确,根据惯例,如果一个线程的当前 SynchronizationContext 为 null,那么它隐式具有一个默认 SynchronizationContext。默认 SynchronizationContext 将其异步委托列队到 ThreadPool,但在调用线程上直接执行其同步委托。因此,其上下文包含所有 ThreadPool 线程以及调用 Send 的任何线程。此上下文“借用”调用 Send 的线程,将它们放入其上下文,直至委托完成。从这种意义上讲,默认上下文可以包含进程中的所有 线程。所以UI应用程序通常有两个同步上下文,一个是UI线程的SynchronizationContext,另一个是包含ThreadPool线程的默认SynchronizationContext。

一般遇到疑问,首先去百度国内论坛,但是继而回去CodeProject相关文章去佐证,好多文章都是从Codeproject上翻译或者浓缩出来的,但这次事件我才发现CodeProject上文章也不靠谱,虽然那上边有好多微软MVP和其他大公司的技术人员,微软的东西还是得去MSDN blog或者 MSDN Magzine上比较靠谱,尤其是看到 Anders  Hejlsberg, Stephen Toub, Erick Lippert, Herb Sutter审阅,就知道这是质量的保证。备忘完毕,还有半天时间,接着去深挖这块东西。

reference:
http://blogs.msdn.com/b/pfxteam/archive/2012/06/15/executioncontext-vs-synchronizationcontext.aspx
http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I
http://msdn.microsoft.com/zh-cn/magazine/gg598924.aspx
http://msdn.microsoft.com/zh-cn/magazine/hh456402.aspx

 

分类:  C#

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于ExecutionContext & SynchronizationContext的详细内容...

  阅读:34次