.NET框架中的ThreadStatic的使用代码是过去年龄的有害遗迹吗?

问题描述:

[ThreadStatic]用于.NET框架中的各个位置,为各种功能提供环境上下文(例如Transaction.Current,用于TransactionScope)。.NET框架中的ThreadStatic的使用代码是过去年龄的有害遗迹吗?

不幸的是,这意味着做一些线程杂耍的功能(ASP.NET,异步关键字代码)切换线程,但不要复制TransactionScope,所以功能如TransactionScope don't work as you might expect

还有另一种机制,CallContext.LogicalGetData(更多here),它在线程切换期间(至少在.NET 4.5中)在整个状态中进行复制。在我看来,如果使用TransactionScope而不是[ThreadStatic],那么它会更好。

如果使用[ThreadStatic]的功能是今天编写的,而不是现有功能的向后兼容性要求,它们是否会使用CallContext.(G|S)etLogicalData写入?

+0

有一些类型的操作本质上是顺序的,使用线程静态存储可以比在方法内传递参数代码之外的任何代码可能感兴趣的代码更清洁。将东西绑定到线程可能会导致异步代码等问题;如果一个框架对单向方法有一流的支持,通过这种方法可以将补充信息传递给它们调用的嵌套方法,而不需要中间层处理它,那将会很好。异步方法然后可以... – supercat

+0

...被赋予它们被调用的环境的只读引用;如果异步方法需要将数据传递给进一步的嵌套方法,那么它们可以构建一个带有指向父代的链接的新环境。 – supercat

实际上,它们具有非常不同的用例。

  • ThreadStatic不能通过await或类似的上下文切换传递值。
  • CallContext不能保留每个线程的值。

所以你看,一个不能代替另一个。 ThreadStatic是一个低级原语。我不认为在CallContext等出现之后,它的用例已经减少了。请注意,它的使用案例消失得很小 - 我认为我最后一次使用它可能是两年前。

我会将诸如Transaction.Current之类的内容描述为滥用TLS。它从来没有为此设计过,所以当TLS似乎打破异步时,它只是因为它从来不应该用于这一点。

是的。我相信这当时似乎是个好主意,但[ThreadStatic]让开发人员陷入了虚假的安全感。 ThreadStatic字段具有许多全局变量的缺点,唯一的优势(不同的线程拥有自己的全局事件实例)具有相应的缺点(如果切换线程,该事情会消失)。这是不是一胜。全局吸引,线程静态全局吸取每一点尽可能多的常规类型。

我在一个相当大的代码基础上工作,几十年的时间里有几十个开发人员(如果你可以在过去几年中离开团队的话,可能会有几百人),[ThreadStatic]会让我们在常规基础。我们已经获得了大量的代码,它们在使用ThreadStatic的时候使用了一个全局的代码,当然,如果你在一个工作线程上执行任何操作,这个代码就会中断。就像我说的那样,我确信当时似乎是一个好主意......但现在它比我们购买我们的产品花费更多。

另一种方法是将相同的对象(HttpContext,Transaction等)传递给依赖它的每个方法。这需要更多的打字,但在我不那么卑微的意见中,从长远来看它仍然更好。