.NET

All about ExecutionContext and SynchronizationContext

.NET

All about ExecutionContext and SynchronizationContext

前言 这篇文章深入探讨了ExecutionContext和SynchronizationContext, 这是大部分开发人员都不需要了解的 .NET 高级领域. SynchronizationContext 我最早关于 SynchronizationContext 了解可能是在 WindowsForm 程序, 当我错误的在其它线程去更新 UI 控件时, 总会出现一个异常 Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on 翻译过来即 跨线程操作无效:控件从创建它的线程以外的线程访问, 例如这个代码片段: private void button_Click(object sender, EventArgs e) { Task.Run(() => { //异常: 跨线程操作无效:控件从创建它的线程以外的线程访问

By FatTiger
C# Async/Await 最佳实践

C#

C# Async/Await 最佳实践

异步不是魔法,也不需要另一个线程等待 很多不理解异步的人总觉得异步是一种魔法操作,认为使用了异步能够增加程序的处理速度。这是一个常见的误解,异步不是魔法,无法加速你程序的运行速度,如果你的方法以前需要一秒钟返回结果使用异步后一样需要一秒钟返回结果,这些人会觉得奇怪,说好的异步会使程序性能提升呢?另一种常见的误解则是,异步也需要线程来执行,只不过使用了线程池线程,会有一个后台线程继续等待异步结果,但事实总是出乎意料:没有额外线程在等待。 让我们一步步解剖异步的线程无需等待到底是什么,假设我们现在需要对文件进行读取: async Task MyMethodAsync() { //异步读取文件 var text = await System.IO.File.ReadAllTextAsync(@"file.text"); //输出文件内容到控制台 System.Console.WriteLine(text); } 当线程执行到 await System.IO.File.ReadAllTextAsync(@"file.text")时,线程会调用操作系统一

By FatTiger
ASP.NET Core 中Session的分布式存储

.NET

ASP.NET Core 中Session的分布式存储

前言 在ASP.NET Core中的Session该如何存储?本文介绍了Session信息在单个应用实例和多个应用实例中的不同存储方式,以及ASP.NET Core在Session数据安全方面做的一些努力。 TL;DR 在ASP.NET Core中使用分布式缓存存储会话时,仅仅将Session进行分布式存储还不够,由于ASP.NET Core的数据安全保护机制,还需要将Data Protection所使用的加密密钥也进行分布式存储,这样才能正确解密Cookies: public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { //将数据保护的秘

By FatTiger
ASP.NET Core 3.0 Razor 修改页面刷新无效

.NET

ASP.NET Core 3.0 Razor 修改页面刷新无效

问题 在ASP.NET Core 3.0中,对Razor页面修改刷新无法展示修改后的内容。 原因 这是由于在ASP.NET Core 3.0中,对Razor视图和Razor页面的运行时编译的支持被移到了单独的程序包中,没有默认启用Razor运行时编译。 解决方案 * 安装Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 在Startup中启用Razor运行时编译: public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment env) { Configuration = configuration; Env = env; } public IWebHostEnvironment Env { get; set; } public IConfiguration Configuration { get; } public voi

By FatTiger

.NET

ThreadStaticAttribute vs ThreadLocal vs AsyncLocal

前言 在.NET程序里,使用static关键字修饰的变量存在于整个程序的生命周期,这使得它可以被多个线程同时访问,这种方式在某些情况下很好用,但是可能需要加锁来处理线程安全问题,在另一些情况下可能只想在线程内共享变量,多个线程之间的变量互相隔离,这就需要使用ThreadStaticAttribute丶ThreadLocal<T>和AsyncLocal<T> TL;DR 实现方式 跨线程 流向辅助线程 static ✔️ ✔️ AsyncLocal ❌ ✔️ ThreadLocal ❌ ❌ ThreadStaticAttribute ❌ ❌ 流向辅助线程 发生线程上下文切换时,能够保存数据并流向到下一个线程,注意,这是单向数据流,辅助线程上更改数据,并不会影响主线程数据(但是你可以通过引用类型来实现主线程数据的同时更改)。 * 线程上下文切换 * new Thread() * new Task() * Task.Run() * ThreadPool.QueueUserWorkItem() * await

By FatTiger
ASP.NET Core中I/O阻塞与线程池爬山

.NET

ASP.NET Core中I/O阻塞与线程池爬山

线程池爬山算法 * CLR的线程池具有最小线程数和最大线程数的限制,默认最小线程数为CPU的逻辑处理器数量,当同时使用的线程数超过最小线程数后,它以适中的速率(例如每秒1或2个)创建新的线程。这意味着当你的线程数超过最小线程数后,超出部分的线程创建请求则需要进行排队,且越后面的线程等待时间越长。 * CLR设计默认线程池数量与CPU逻辑处理器数量相同是有原因的,两个好处: * 线程数过多的情况下,CPU需要在多个线程间进行切换,这会导致额外的线程切换开销,线程数越多则CPU大部分时间都花在了切换线程上下文上。 * 如果某个方法是阻塞的,那么大量的请求进来会导致线程无限制的被创建,会瞬间消耗大量的内存。 Practice * 我们可以简单的创建一个NET Core Console程序进行验证 static void Main(string[] args) { var processThreads = 0; while (true) { Task.Factory.StartNew(() => {

By FatTiger

.NET

NET Core IOptionsMonitor的使用

最近在使用IOptionsMonitor时,发现OnChange方法无法回调,代码如下: Startup.cs public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.Configure<MyConfig>(config => { config.Value = Configuration.GetValue<string>("MyConfig:Value"); }); services.AddSingleton<SingletonService>(); } SingletonService.cs private MyConfig myConfig; public SingletonService(IOptionsMonitor<MyConfig> optionsMonitor) { myConfig = optionsMonitor.CurrentValue;

By FatTiger