C#

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

.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 Framework

Globalization and localization in ASP.NET Framework

Globalization and Localization Globalization指将应用程序设计为支持多个语言和文化的过程,Localization则意为将已经Globalization的应用程序设置为特定区域输出的过程。例如将应用程序的输出字符和UI都使用资源文件进行配置,可输出多个不同语言则应用程序已经准备好全球化过程,而根据浏览器语言或者Cookie设置获取特定的区域语言则称之为本地化过程。 Best Practices 新建ASP.NET Framework应用程序后,新建App_GlobalResources文件夹并在下面新建三个资源文件: 其中,Resource.resx为基准资源文件,Resource.en-US则为en-US区域对应的资源文件,Resource.zh-CN则为zh-CN区域对应的资源文件,应当说明的是,所有资源文件的字符串Key应当与Resource.resx资源文件中的Key相一致,Value则为对应区域的本地化字符串。 接下来在Resource.resx中新增一个SYSTEM_NAME用来表示当前系统信息,相应的Resource.e

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

.NET Core

ASP.NET Core 中动态写入配置文件

由于上了K8S集群化管理,配置自然要从远程读取,使用配置中心后,应用程序打包成Docker Image时只有一个appsettings.json,程序启动时在Startup.cs中从远程加载配置后创建本地的appsettings.{ASPNETCORE_ENVIRONMENT}.json。大概代码如下: public void ConfigureServices(IServiceCollection services) { //加载appsettings.json中的ACM配置 services.Configure<AliyunConfig>(Configuration.GetSection("AliyunACM")); //封装好的从远程加载配置的方法,读取到远程配置后则会创建出appsettings.{ASPNETCORE_ENVIRONMENT}.json文件 services.AddAliyunACM(); } 加载配置中心的代码会放在读取其它配置之前,这样读取其它配置时就应该是远程的配置项。但是实际运行时却无法读取到变更后的配置项,Deb

By FatTiger