浅析C#中的AsyncLocal与ThreadLocal
在C#中,当多个线程同时访问同一个变量时,需要使用线程安全的方式保护变量,避免数据竞争。AsyncLocal和ThreadLocal就是两种常用的线程安全技术。
引言
AsyncLocal
AsyncLocal是.NET Framework 4.6中引入的一种用于在异步代码中存储和检索数据的新机制。它类似于ThreadLocal,但与线程模型无关。
ThreadLocal
ThreadLocal是.NET Framework中的一个非常有用的类。它可以将数据存储在线程的本地存储区中,以便多个线程可以独立地使用相同的数据结构,而不会导致冲突或竞争条件。
AsyncLocal vs ThreadLocal
- AsyncLocal可以跨异步上下文流动,而ThreadLocal只能在同一个线程中起作用。
- AsyncLocal在异步操作之间共享数据,而ThreadLocal针对每个线程存储单独的数据。
由于AsyncLocal的功能更加强大,所以它更适合在异步代码中使用。
示例
下面给出两个示例来说明AsyncLocal的用法。
示例1:在异步请求中获取TraceID
public class TraceIdMiddleware
{
private readonly RequestDelegate _next;
private static readonly AsyncLocal<string> TraceId = new AsyncLocal<string>();
public TraceIdMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
TraceId.Value = Guid.NewGuid().ToString();
context.Response.OnStarting(() =>
{
context.Response.Headers.Add("X-Trace-Id", new string[] { TraceId.Value });
return Task.CompletedTask;
});
await _next(context);
}
}
上述代码中,我们使用AsyncLocal存储了TraceID,利用TraceID可以跨异步方法调用。
示例2:在异步请求中获取当前用户身份
public static class CurrentUser
{
private static readonly AsyncLocal<AppUser> _currentUser = new AsyncLocal<AppUser>();
public static AppUser Current
{
get => _currentUser.Value;
set => _currentUser.Value = value;
}
}
public class UserController : ControllerBase
{
[HttpGet("current")]
public ActionResult GetCurrentUser()
{
return Ok(CurrentUser.Current);
}
[HttpGet("set")]
public ActionResult SetCurrentUser()
{
var currentUser = new AppUser
{
Id = 1,
Name = "张三"
};
CurrentUser.Current = currentUser;
return Ok();
}
}
上述代码中,我们使用AsyncLocal存储用户身份。在请求开始时,我们将当前用户存储到AsyncLocal中。在后续的操作中,我们可以通过静态属性获取当前用户,而不用担心多线程并发访问的问题。
总结
AsyncLocal是.NET Framework 4.6中引入的一种用于在异步代码中存储和检索数据的新机制。与之相比,ThreadLocal只能在同一个线程中起作用。在异步场景中,使用AsyncLocal可以更加方便地存储和获取数据。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅析C#中的AsnycLocal与ThreadLocal - Python技术站