1、(SynchronizationContext)同步上下文的作用
SynchronizationContext 顾名思义是同步上下文的意思。利用此对象可以实现线程间数据的同步、异步访问 ,其实就是实现线程之间通讯的。
SynchronizationContext(同步上下文),是一个抽象类,它表示线程上下文,用于协调异步方法(或代理线程)的回调。
使用同步上下文可以使得异步方法(或代理线程)的回调在正确的线程上下文中进行,这样可以避免由于线程上下文切换引发的问题,同时可以更好地掌控异步操作的生命周期。
其实,同步上下文是一种编程模型,它允许多个线程之间的协作,使得程序员可以更加轻松地编写异步代码。
class Program { static Thread _workThread; static SynchronizationContext _mainThreadSynContext; static void Main(string[] args) { _mainThreadSynContext = SynchronizationContext.Current; if (_mainThreadSynContext == null) { _mainThreadSynContext = new SynchronizationContext(); } _workThread = new Thread(new ThreadStart(DoWork)); _workThread.Start(); Console.ReadLine(); } static void DoWork() { int a = 10; _mainThreadSynContext.Post(new SendOrPostCallback(ThreadCallBack),a); } static void ThreadCallBack(object state) { Console.WriteLine((int)state); Console.ReadLine(); } }
2、创建(SynchronizationContext)同步上下文的方法
1)直接new创建一个SynchronizationContext同步上下文对象。
2)winform程序通过SynchronizationContext.Current获取UI线程的同步上下文对象。
3)AsyncOperation和AsyncOperationManager类来操作同步上下文对象,不直接访问同步上下文对象(SynchronizationContext),推荐这程方法。
3、(SynchronizationContext)同步上下文的Send和Post方法
看了一些解释Send和Post方法,感觉弄得很复杂,我感觉其实简单来说,
1)Send方法就是同步调用,在当前线程上调用委托。
2)Post方法就是异步调用,在线程池中的线程调用委托。
4、示例代码
1)(SynchronizationContext)同步上下文使用示例代码
using System; using System.Threading; namespace SynchronizationContextExample { public class MySynchronizedClass { private Thread workerThread; private SynchronizationContext context; public event EventHandler SomethingHappened; public MySynchronizedClass() { //获取当前SynchronizationContext非常重要对象在构造函数中。我们想要的 //属于线程的SynchronizationContext对象 //这个对象正在被创建。 //context= SynchronizationContext.Current;当前线程可能没有SynchronizationContext对象;该线程尚未为设置SynchronizationContext对象。 //如果是这样,我们可以通过创建SynchronizationContext来简化 if(context == null) { context = new SynchronizationContext(); } workerThread = new Thread(new ThreadStart(DoWork)); workerThread.Start(); } private void DoWork() { context.Post(new SendOrPostCallback(delegate(object state) { EventHandler handler = SomethingHappened; if(handler != null) { handler(this, EventArgs.Empty); } }), null); } } }
2)使用AsyncOperation和AsyncOperationManager类示例代码
using System; using System.Threading; using System.ComponentModel; namespace SynchronizationContextExample { public class MySynchronizedClass { private Thread workerThread; private AsyncOperation operation; public event EventHandler SomethingHappened; public MySynchronizedClass() { operation = AsyncOperationManager.CreateOperation(null); workerThread = new Thread(new ThreadStart(DoWork)); workerThread.Start(); } private void DoWork() { operation.Post(new SendOrPostCallback(delegate(object state) { EventHandler handler = SomethingHappened; if(handler != null) { handler(this, EventArgs.Empty); } }), null); operation.OperationCompleted(); } } }
在编写异步代码时,同步上下文是一个非常重要的概念。它可以确保异步操作的回调在正确的线程上下文中执行,同时可以更加轻松地编写可读、可维护的异步代码。在.NET中,常见的同步上下文类型包括WindowsFormsSynchronizationContext、TaskScheduler、AspNetSynchronizationContext等。
WindowsFormsSynchronizationContext主要用于Windows Forms应用程序。当异步操作完成时,它会将结果返回到主线程,使得我们可以更新UI。
// 创造同步上下文 SynchronizationContext ctx = WindowsFormsSynchronizationContext.Current; // 异步操作 var result = await Task.Run(() => { return SomeLongOperation(); }); // 回调到主线程 ctx.Post(state => { textBox1.Text = result.ToString(); }, null);
2、TaskScheduler
TaskScheduler是一个线程池,当异步任务完成时,它会使用回调线程池来处理异步回调。
// 创造同步上下文 var scheduler = TaskScheduler.FromCurrentSynchronizationContext(); // 异步操作 Task.Run(() => { return SomeLongOperation(); }) .ContinueWith(task => { // 处理结果 textBox1.Text = task.Result.ToString(); }, CancellationToken.None, TaskContinuationOptions.None, scheduler);
3、AspNetSynchronizationContext
AspNetSynchronizationContext主要用于ASP.Net应用程序。当异步操作完成时,它会将结果返回到AspNet请求处理程序中,使得我们可以更新Web UI。
// 创造同步上下文 SynchronizationContext ctx = new AspNetSynchronizationContext(); // 异步操作 var result = await Task.Run(() => { return SomeLongOperation(); }); // 回调 ctx.Post(state => { Response.Write(result.ToString()); }, null);
与async/await的结合使用
同步上下文可以与async/await一起使用,这样可以使得异步代码更加可读、可维护。
private async void Button_Click(object sender, RoutedEventArgs e) { // 运行异步方法 var result = await LongOperationAsync(); // 更新UI Label.Content = result.ToString(); } private async Task LongOperationAsync() { // 访问网络 await Task.Delay(TimeSpan.FromSeconds(5)); // 返回结果 return 42; }