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. Linux基础_7_文本显示

    注:实质是针对标准输出文本的各种骚操作! 简单查看 注:初略加工后进行显示. cat -n 文件名 #查看文件内容并显示行号 tac 文件名 #逆序查看 more 文件名 less 文件名 #按?搜索 ...

  2. 归纳学习(Inductive Learning),直推学习(Transductive Learning),困难负样本(Hard Negative)

    归纳学习(Inductive Learning): 顾名思义,就是从已有训练数据中归纳出模式来,应用于新的测试数据和任务.我们常用的机器学习模式就是归纳学习. 直推学习(Transductive Le ...

  3. 4.Future对象

    asyncio.Future对象 Future是Task类的基类 Task对象内部await结果的处理是基于Future对象来的 async def main(): # 获取当前事件循环 loop = ...

  4. 7.websocket收发消息

    客户端主动向服务端发起websocket连接,服务端接收到连接后通过(握手) 客户端 websocket socket = new WebSocket('ws://127.0.0.1/ws/'); 服 ...

  5. 我的Vue之旅 09 数据数据库表的存储与获取实现 Mysql + Golang

    第四期 · 将部分数据存储至Mysql,使用axios通过golang搭建的http服务器获取数据. 新建数据库 DROP DATABASE VUE; create database if not e ...

  6. onps栈移植说明(1)——onps栈的配置及裁剪

    onps栈的移植涉及几个部分:1)系统配置及裁剪:2)基础数据类型定义:3)RTOS适配层实现:4)编写网卡驱动并注册网卡.本文作为onps栈移植的指导性文件将给出一般性的移植说明及建议,具体的移植样 ...

  7. jupyter初体验

    安装: 1.若是已经安装了anaconda,则通过  jupyter notebook 命令进入: 2.若是只安了python: pip3 install --upgrade pip   对pip进行 ...

  8. day12-Servlet02

    Servlet02 6.GET和POST请求的分发处理 开发Servlet,通常编写doGet,doPost方法.来对表单的get和post请求进行分发处理 例子 在web文件夹下面创建一个html页 ...

  9. 通过jmeter,造50个单位的并发用户数据(用户从上至下每50个单位依次排序)

    单位数据:loginfoll.csv         #50个单位的信息(agencyCode,passwd,agencyname,rgcode) 用户数据:50个单位,每个单位200个用户(用户名为 ...

  10. 云原生之旅 - 14)遵循 GitOps 实践的好工具 ArgoCD

    前言 Argo CD 是一款基于 kubernetes 的声明式的Gitops 持续部署工具. 应用程序定义.配置和环境都是声明式的,并受版本控制 应用程序部署和生命周期管理都是自动化的.可审计的,并 ...