Bre*_*ias 44 c# .net-core asp.net-core
对于.NET Core,AsyncLocal它是替代品CallContext.但是,目前还不清楚在ASP.NET Core中使用它是多么"安全".
在ASP.NET 4(MVC 5)和更早版本中,ASP.NETCallContext的线程敏捷性模型变得不稳定.因此,在ASP.NET中,实现每请求逻辑上下文行为的唯一安全方法是使用HttpContext.Current.Items.在幕后,HttpContext.Current.Items实现了CallContext,但它以一种对ASP.NET安全的方式完成.
相反,在OWIN/Katana Web API的上下文中,线程敏捷性模型不是问题.在仔细考虑如何正确处理它之后,我能够安全地使用CallContext .
但现在我正在处理ASP.NET Core.我想使用以下中间件:
public class MultiTenancyMiddleware
{
private readonly RequestDelegate next;
static int random;
private static AsyncLocal<string> tenant = new AsyncLocal<string>();
//This is the new form of "CallContext".
public static AsyncLocal<string> Tenant
{
get { return tenant; }
private set { tenant = value; }
}
//This is the new verion of [ThreadStatic].
public static ThreadLocal<string> LocalTenant;
public MultiTenancyMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
//Just some garbage test value...
Tenant.Value = context.Request.Path + random++;
await next.Invoke(context);
//using (LocalTenant = new AsyncLocal<string>()) {
// Tenant.Value = context.Request.Path + random++;
// await next.Invoke(context);
//}
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,上面的代码似乎工作正常.但至少有一个红旗.在过去,确保将CallContext其视为每次调用后必须释放的资源至关重要.
现在我看到没有不言而喻的"清理"方式AsyncLocal.
我列出了代码,注释掉了,显示了如何ThreadLocal<T>工作.它是IDisposable,因此它有一个明显的清理机制.相反,AsyncLocal事实并非如此IDisposable.这令人不安.
这是因为AsyncLocal尚未处于发布候选条件吗?或者这是因为真的不再需要进行清理了吗?
即使AsyncLocal在上面的示例中正确使用,ASP.NET Core中是否存在任何种类的旧学校"线程敏捷性"问题,这些问题会使这个中间件变得不可行?
对于那些不熟悉CallContextASP.NET应用程序中的问题的人来说,在这篇SO帖子中,Jon Skeet引用了对该问题的深入讨论(后者又引用了Scott Hanselman的评论).这个"问题"不是一个错误 - 它只是一个必须仔细考虑的情况.
此外,我个人可以证明这种不幸的行为.当我构建ASP.NET应用程序时,我通常将负载测试作为自动化测试基础架构的一部分.在负载测试期间,我可以看到CallContext变得不稳定(可能有2%到4%的请求显示CallContext已损坏.我也看到过Web API GET具有稳定CallContext行为的情况,但POST操作都是不稳定的.实现的唯一方法总稳定性是依赖于HttpContext.Current.Items.
但是,在ASP.NET Core的情况下,我不能依赖HttpContext.Items ...没有这样的静态访问点.我还无法为我正在修补的.NET Core应用程序创建负载测试,这也是我自己没有回答这个问题的部分原因.:)
再说一遍:请理解我正在讨论的"不稳定性"和"问题"根本不是一个错误.CallContext没有任何缺陷.问题只是ASP.NET使用的线程调度模型的结果.解决方案只是知道问题存在,并相应地进行编码(例如,在ASP.NET应用程序内部时使用
HttpContext.Current.Items而不是代码CallContext).
我对这个问题的目标是了解这个动态如何在ASP.NET Core中应用(或不应用),这样我在使用新AsyncLocal构造时不会意外地构建不稳定的代码.
小智 15
我只是查看CoreClr的ExecutionContext类的源代码:https: //github.com/dotnet/coreclr/blob/775003a4c72f0acc37eab84628fcef541533ba4e/src/mscorlib/src/System/Threading/ExecutionContext.cs
根据我对代码的理解,异步本地值是每个ExecutionContext实例的字段/变量.它们不基于ThreadLocal或任何特定于线程的持久数据存储.
为了验证这一点,在我使用线程池线程进行测试时,当重用相同的线程池线程时,无法访问异步本地值中的实例,并且在下一个GC周期调用"左"实例的用于清理自身的析构函数,这意味着该实例按预期进行GCed.
Ale*_*lex 10
如果有人AsyncLocal在ASP.NET 经典(非核心)应用程序中使用谷歌搜索是否“安全” (一些评论者一直在问这个问题,并且我看到一个已删除的答案询问相同的)。
我写了一个模拟asp.net的ThreadPool行为的小测试
AsyncLocal 即使线程池重用现有线程,请求之间也始终清除。所以在这方面它是“安全的”,没有数据会泄漏到另一个线程。
但是,AsyncLocal即使在相同的上下文中也可以清除(例如在 global.asax 中运行的代码和在控制器中运行的代码之间)。因为 MVC 方法有时会在与非 MVC 代码分离的线程上运行,请参阅此问题,例如:asp.net mvc 4, thread changed by model binding?
使用ThreadLocal是不安全的 b/c 它在线程池中的线程被重新使用后保留该值。切勿在 Web 应用程序中使用 ThreadLocal。我知道问题与 ThreadLocal 无关,我只是向考虑使用它的人添加此警告,抱歉。
在 ASP.NET MVC 5 .NET 4.7.2 下测试。
总的来说,在您无法直接访问后者的情况下,它AsyncLocal似乎是短期缓存内容的完美替代品HttpContext.Current。不过,您最终可能会更频繁地重新计算缓存值,但这不是大问题。
| 归档时间: |
|
| 查看次数: |
9134 次 |
| 最近记录: |