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. 关于Springboot启动报错 Whitelabel Error Page: This application has no explicit mapping

    Whitelabel Error Page This application has no explicit mapping for /error, so you are seeing this as ...

  2. java.lang.ClassNotFoundException: Cannot find class: “com.mysql.jdbc.Driver“的报错问题

    @Testpublic void testConnectionTest5() throws Exception { //1.读取配置文件,获取4个基本信息 InputStream is = Conne ...

  3. 知识图谱-生物信息学-医学顶刊论文(Briefings in Bioinformatics-2021):MPG:一种有效的自我监督框架,用于学习药物分子的全局表示以进行药物发现

    6.(2021.9.14)Briefings-MPG:一种有效的自我监督框架,用于学习药物分子的全局表示以进行药物发现 论文标题:An effective self-supervised framew ...

  4. costool - 腾讯云cos快捷工具。

    目录 使用截图 使用方法 配置文件 安装方法 其他 一个腾讯云cos(对象存储)非官方快速上传和下载的工具,使用官方go-sdk二次开发.可以用于以下场景. 备份一些配置文件,比如.bashrc .v ...

  5. CodeTON Round 3 (C.差分维护,D.容斥原理)

    C. Complementary XOR 题目大意: 给你两个01串ab,问你是否可以通过一下两种操作在不超过n+5次的前提下将两个串都变为0,同时需要输出可以的操作方案 选择一个区间[l,r] 将串 ...

  6. dockerNginx代理本地目录

    dockerNginx代理本地目录 ssl_certificate cert/5900588_test.zk.limengkai.work.pem; ssl_certificate_key cert/ ...

  7. htaccess如何配置隐藏index.php文件

    <IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine On RewriteCond %{RE ...

  8. Marktext语法——Emoji表情大全

    个人名片: 对人间的热爱与歌颂,可抵岁月冗长 Github‍:念舒_C.ying CSDN主页️:念舒_C.ying 个人博客 :念舒_C.ying People ️ ️ ️ ️ ‍♀️ ‍♀️ ‍♂ ...

  9. 在业务逻辑中,经常会有父组件调用子组件方法的情况,vue2.0 和 vue3.0 的使用中有些不一样,在这里总结下。

    在业务逻辑中,经常会有父组件调用子组件方法的情况,vue2.0 和 vue3.0 的使用中有些不一样,在这里总结下. vue2.0 中的使用方法 父组件: <template> <d ...

  10. python小练习:涉及print,json,numpy

    枚举参考文件夹中的文件,并与待比较文件件中的同名文件比较是否一致. #! /usr/bin/python3.6 # -*- coding:utf-8 -*- import os import sys ...