title: .NET SynchronizationContext
date: 2022-12-06 09:38:53
tags:
- .NET

前言

最近在看CAP的源码,经常能看到ConfigureAwait(false),例如下面这一段:

public async Task PublishAsync(string stream, NameValueEntry[] message)
{
await ConnectAsync()
.ConfigureAwait(false); await _redis!.GetDatabase().StreamAddAsync(stream, message)
.ConfigureAwait(false);
}

不明白这一句话的意义,于是乎查了一下资料,这里记录总结一下

SynchronizationContext是什么

先看一下MSDN上官方的解释:

SynchronizationContext是一个基类,它提供了没有同步的线程自由的上下文。实现了这个类的同步模型的类允许公共语言运行时内部的异步/同步操作能够在合适的同步模型上允许。该模型还简化了托管应用程序必须遵循的一些需求,以便在不同的同步环境下正确工作。同步模型的提供者可以扩展这个类,并为这些方法提供他们自己的实现。

链接:https://learn.microsoft.com/en-us/dotnet/api/system.threading.synchronizationcontext?view=net-7.0

听起来非常的官方,但是上面这句话的大体意思是想说不同的框架在线程之间的通信方式不同,我们可能想要在正确的上下文中调用特定的代码,比如WPF中的Dispatcher.BeginInvoke允许我们从另一个线程调用UI线程来执行具体的代码,SynchronizationContext类就是这些实现的一个抽象类,它提供了一些方法,让我们可以在不同的上下文中执行代码。

SynchronizationContext公开了几个方法,我们可以通过这些方法来实现不同的上下文之间的通信,其中比较重要的一个方法就是Post,它的定义如下:

public virtual void Post(SendOrPostCallback d, object? state);

这个方法的作用是将一个委托放入队列中,然后在合适的时候执行,默认的实现是通过ThreadPool.QueueUserWorkItem来实现的,也就是说,这个方法的默认实现是将委托放入线程池中,然后在合适的时候执行。但是,我们可以通过继承SynchronizationContext类来实现自己的同步上下文,然后重写Post方法来实现不同的同步上下文,比如WPF中的DispatcherSynchronizationContext就是通过重写Post方法来实现的,调用方式就是通过调用Dispatcher.BeginInvoke来实现。

从名字上来看,SynchronizationContext是我们当前代码运行的一个上下文环境,也就是说在异步程序中,当我们把一段业务代码委托给另一个线程执行时,我们捕获了当前的上下文环境,放到SynchronizationContext中,然后把它放到了Task对象上,重点是我们可以捕获当前环境并传递给另一个线程,这样我们可以在另一个线程中恢复当前的上下文环境,然后执行我们的代码。

为什么需要SynchronizationContext?

有时候我们需要在另一个线程中执行一段代码,比如我们需要在另一个线程中更新UI,这时候我们就需要在另一个线程中恢复当前的上下文环境,然后执行我们的代码,这就是SynchronizationContext的作用。

具体原因这里不细说,了解WPF、Winform应该都知道UI控件的属性只能在UI线程更新

不是所有的框架都有SynchronizationContext

不是所有的框架都有SynchronizationContext,比如Asp.Net Core就没有,参考 https://stackoverflow.com/questions/18097471/what-does-synchronizationcontext-do

所以有些时候我们会发现在很多开源框架内都会使用ConfigureAwait(false)来禁用SynchronizationContext,这样做的目的就是为了避免在不同的上下文中执行代码,比如在Asp.Net Core中,我们不需要在另一个线程中恢复当前的上下文环境,因为Asp.Net Core没有SynchronizationContext,所以我们可以使用ConfigureAwait(false)来禁用SynchronizationContext,这样做的好处是可以提高性能,因为不需要在不同的上下文中执行代码。

同时需要注意的是,async await默认会捕获当前的运行上下文,如果上下文为空的话,则默认会在TaskScheduler.Default上执行,也就是在线程池内的任意一个线程执行,当然这个线程也有可能是UI线程或执行它的线程

每个线程都有一个SynchronizationContext

每个线程都有一个SynchronizationContext,这意味着如果我们将工作从一个线程池委托给另一个线程,我们可以获得当前运行环境的快照并将其传递给另一个线程

参考链接

  1. https://hamidmosalla.com/2018/06/24/what-is-synchronizationcontext/
  2. https://stackoverflow.com/questions/18097471/what-does-synchronizationcontext-do

NET-SynchronizationContext的更多相关文章

  1. 线程处理模型 由于 SynchronizationContext 引起的死锁问题解决

    由于GUI 应用程序 不能使用线程池的线程更新UI,只能使用 GUI 线程更新,所以在 await 前后需要保证是同一个 GUI 线程 ASP.NET 程序 的线程处理客户端请求的时候,需要假定客户端 ...

  2. 搞懂 SynchronizationContext(第一部分)【翻译】

    SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...

  3. 搞懂 SynchronizationContext

    SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...

  4. 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationContext, CoreDispatcher, ThreadLocal, ThreadStaticAttribute

    [源码下载] 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationCont ...

  5. 【C#】【Thread】SynchronizationContext线程间同步

    SynchronizationContext在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯. 需要注意的是,不是每个线程都附加SynchronizationContext这个对象, ...

  6. SynchronizationContext的研究之一(非WPF及Forms)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. SynchronizationContext一篇

    SynchronizationContext context; 最近写代码用到了这个,特别记录一下. 作用如下: // 摘要: // 提供在各种同步模型中传播同步上下文的基本功能. public cl ...

  8. 译文: async/await SynchronizationContext 上下文问题

    async / await 使异步代码更容易写,因为它隐藏了很多细节. 许多这些细节都捕获在 SynchronizationContext 中,这些可能会改变异步代码的行为完全由于你执行你的代码的环境 ...

  9. 理解SynchronizationContext,如何在Winform里面跨线程访问UI控件

    SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文. 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为.此模型 ...

  10. 【.NET异步编程系列2】掌控SynchronizationContext避免deadlock

    引言: 多线程编程/异步编程非常复杂,有很多概念和工具需要去学习,贴心的.NET提供Task线程包装类和await/async异步编程语法糖简化了异步编程方式. 相信很多开发者都看到如下异步编程实践原 ...

随机推荐

  1. JVM中的方法区

    JVM中的方法区 方法区存储什么? 用于存储已被虚拟机加载的类型信息.常量.静态变量.即时编译器编译后的代码缓存 1.类型信息 对每个加载的类型(类class.接口interface.枚举.注解)jv ...

  2. 手把手教你从安装CentOS7.4镜像开始,搭建IoT视频监控系统

    摘要:在CentOS7.4服务器版本的环境下安装nginx服务器.配置文件服务器.流媒体服务器. 本文分享自华为云社区<华为云ECS服务器安装CentOS7.4镜像,部署GINX服务器.搭建物联 ...

  3. python-代码编程规范

    命名 常用简写 名称相关 # 信息 information: info # 功能 function : func # 数量 quantity:qty PYQT相关 button : btn_ chec ...

  4. ubuntu20.04修改静态ip不生效问题

    一.前言 最近从头开始配置hadoop的时候,由于想切换到NAT模式下配置hadoop,但在修改ip的时候发现设置了静态ip,但ip不生效,查了很多资料,发现由于配置信息写错了. 二.解决问题 ifc ...

  5. 46.drf过滤、搜索、排序

    DRF的过滤类 drf过滤器在filters模块中,主要有四个类 BaseFilterBackend:过滤基类,留好占位方法待后续继承 SearchFilter:继承BaseFilterBackend ...

  6. 第一百零八篇:最常用的基本数据类型(Number,String类型)

    好家伙, 1.Number类型 从名称中我们可以得出,这是一个存放数值的类型, 不同的数值类型相应地也有不同的数值字面量格式 number类型可以储存不同进制的数(不常用就是了) 八进制:在数前加一个 ...

  7. Oracle中新建数据表的两种方法

    首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...

  8. Go语言核心36讲37

    你好,我是郝林,今天我们继续来分享并发安全字典sync.Map的内容. 我们在上一篇文章中谈到了,由于并发安全字典提供的方法涉及的键和值的类型都是interface{},所以我们在调用这些方法的时候, ...

  9. CentOS 7.x字符界面安装图形界面方法

    1. 配置好yum源,可以使用光盘镜像源,也可以使用网络源. 阿里源下载示例: wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.ali ...

  10. 深度学习之Tensorflow入门

    声明 本文参考[中文][吴恩达课后编程作业]Course 2 - 改善深层神经网络 - 第三周作业_何宽的博客-CSDN博客我对这篇博客加上自己的理解,力求看懂 本文所使用的资料已上传到百度网盘[点击 ...