[ThreadStatic]属性如何工作?我假设编译器会发出一些IL来填充/检索TLS中的值,但是看一下反汇编它似乎不会在那个级别上执行.
作为跟进,如果你把它放在非静态成员身上会发生什么?我们有一个开发人员犯了这个错误,编译器甚至没有提出警告.
更新
第二个问题在这里回答:使用Static C#修改ThreadStatic
[ThreadStatic]在ThreadLocal<T>使用泛型时使用属性定义.为什么选择不同的设计方案?在这种情况下使用泛型over属性有哪些优缺点?
我自己写了一个多线程随机生成器
public static class MyRandGen
{
private static Random GlobalRandom = new Random();
[ThreadStatic]
private static Random ThreadRandom = new Random(SeedInitializer());
private static int SeedInitializer()
{
lock (GlobalRandom) return GlobalRandom.Next();
}
public static int Next()
{
return ThreadRandom.Next();
}
}
Run Code Online (Sandbox Code Playgroud)
但是,它在抛出Next()时抛出了NullReferenceException,我不明白.这种初始化ThreadStatic字段是否被禁止?
我知道我可以检查每次都是否已初始化该字段,但这不是我正在寻找的解决方案.
我最近阅读了这篇关于标记为ThreadStatic的字段性能不佳的帖子 - 它们显然比正常的字段访问慢60倍..NET 4的ThreadLocal <T>执行得更好吗?
有没有提供高性能线程专用存储的替代方案?
我有一个组件需要static在每个线程之前存储值.它是一个通用组件,可以在许多场景中使用,而不仅仅在ASP.NET中使用.
我正在考虑使用该[ThreadStatic]属性来实现我的目标.假设它在ASP.NET场景中也能正常工作,因为我假设每个Request都在自己的线程中调用.
经过一些研究后,我发现Scott Hanselman 撰写的这篇博客文章说[ThreadStatic]在ASP.NET中使用时要小心.
然而,大多数评论(在帖子下面)都不同意斯科特写的,说请求总是在一个线程中运行,并且该线程不会被另一个请求同时使用.这也是我所相信的,但我很乐意在这里对你的专家有一些看法.
更新:正如我所预料的那样,社区对此问题提出的合理建议是"衡量和看到".chibacity发布了一些答案,其中包含一些非常好的测试,为我做了这个; 同时,我写了一个我自己的考试; 我看到的性能差异实际上是如此巨大,以至于我不得不写一篇关于它的博客文章.
但是,我也应该承认Hans的解释,该ThreadStatic属性确实不是免费的,实际上依赖于CLR辅助方法来实现其魔力.这使得在任何情况下应用是否适当的优化很明显.
对我来说,好消息是,就我而言,它似乎已经取得了很大的进步.
我有一个方法(在许多其他事情中)为一些局部变量实例化一些中等大小的数组(~50个元素).
经过一些分析后,我发现这种方法是性能瓶颈.并不是说这种方法需要很长时间才能打电话; 相反,它被简单地调用很多次,非常快(在一个会话中数十万到数百万次,这将是几个小时).因此,即使对其性能进行相对较小的改进也是值得的.
在我看来,也许不是在每次调用时分配一个新数组,我可以使用标记的字段[ThreadStatic]; 每当调用该方法时,它将检查该字段是否在当前线程上初始化,如果没有,则初始化它.从那时起,同一个线程上的所有调用都会有一个阵列都准备就绪.
(该方法初始化数组本身中的每个元素,因此在数组中使用"陈旧"元素应该不是问题.)
我的问题很简单:这看起来是个好主意吗?ThreadStatic以这种方式使用属性是否存在缺陷(即,作为性能优化来降低实例化局部变量的新对象的成本)我应该知道哪些?一个ThreadStatic领域本身的表现可能不是很好; 例如,是否有很多额外的"东西"在后台发生,有自己的成本,使这个功能成为可能?
对我来说,我甚至试图优化像50元素阵列那样便宜(?)的东西是错误的 - 如果是这样的话,绝对让我知道 - 但一般的问题仍然存在.
我正在研究桌面winform应用程序的一个非常大的旧代码库.在这个代码库中,有很多操作在后台线程中执行,主要是使用BackgroundWorker.
此代码库中的一个常见模式是通过将工件绑定到正在执行的线程来隐藏复杂性.例如,数据库连接和事务存储在[ThreadStatic]字段中.
我正在尝试更改此设置,并开始使用async/await代码,并从在池的任何线程中运行任务中受益,并允许任务通过使用继续在任何其他线程中执行ConfigureAwait(false).我知道这[ThreadStatic]不好玩async/await,我已经阅读了几个答案,建议使用AsyncLocal<T>.
鉴于我正在开发大型代码库,如前所述,我无法async/await一次性切换到任何地方,我必须逐步进行此更改.所以之前的代码[ThreadStatic]将改为AsyncLocal<T>,但代码的大部分将继续使用,BackgroundWorker并且不会访问单行async/await代码.
问题
这会有用吗?我需要能够定义某种可以使用我的新async/await代码的上下文流程,并且还继续使用我的旧非异步代码,这些代码依赖于[ThreadStatic]保持每个线程内容彼此独立.
如果我完全错了,走错了路,建议非常受欢迎.
我写了一个小的测试程序,并且很惊讶为什么lock {}解决方案比无锁更快但是[ThreadStatic]属性超过静态变量.
[ThreadStatic]片段:
[ThreadStatic]
private static long ms_Acc;
public static void RunTest()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int one = 1;
for (int i = 0; i < 100 * 1000 * 1000; ++i) {
ms_Acc += one;
ms_Acc /= one;
}
stopwatch.Stop();
Console.WriteLine("Time taken: {0}", stopwatch.Elapsed.TotalSeconds);
}
Run Code Online (Sandbox Code Playgroud)
lock {}摘要:
private static long ms_Acc;
private static object ms_Lock = new object();
public static void RunTest()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int one …Run Code Online (Sandbox Code Playgroud) 我在我的asp.net mvc3应用程序(在IIS7上)使用专有的IoC机制,在[ThreadStatic]字段中保存状态,因此依赖于假设HttpApplication.BeginRequest,HttpApplication.EndRequest和整个同步执行(单个)他们所涉及的请求是在同一个线程上执行的.
这个假设是否正确?
我想知道TransactionScope类如何工作以保持不同方法调用之间的事务(不需要将其作为参数传递),我开始怀疑.我对这个问题有两点考虑:
通过Telerik JustDecompile查看TransactionScope的实现,我发现当前事务存储在System.Transactions.ContextData类的ThreadStatic成员中(下面的代码).
internal class ContextData
{
internal TransactionScope CurrentScope;
internal Transaction CurrentTransaction;
internal DefaultComContextState DefaultComContextState;
[ThreadStatic]
private static ContextData staticData;
internal WeakReference WeakDefaultComContext;
internal static ContextData CurrentData
{
get
{
ContextData contextDatum = ContextData.staticData;
if (contextDatum == null)
{
contextDatum = new ContextData();
ContextData.staticData = contextDatum;
}
return contextDatum;
}
}
public ContextData()
{
}
}
Run Code Online (Sandbox Code Playgroud)
CurrentData属性由TransactionScope的PushScope()方法调用,最后一个属性由大多数TransactionScope构造函数使用.
private void PushScope()
{
if (!this.interopModeSpecified)
{
this.interopOption = Transaction.InteropMode(this.savedCurrentScope);
}
this.SetCurrent(this.expectedCurrent);
this.threadContextData.CurrentScope = this;
}
public TransactionScope(TransactionScopeOption scopeOption)
{
// …Run Code Online (Sandbox Code Playgroud) threadstatic ×10
c# ×6
.net ×3
asp.net ×2
thread-local ×2
async-await ×1
attributes ×1
generics ×1
optimization ×1
performance ×1
random ×1
static ×1