4

[ThreadStatic]用于 .NET 框架中的各个地方,为各种功能提供环境上下文(例如Transaction.Current,用于TransactionScope)。

TransactionScope不幸的是,这意味着执行一些线程杂耍(ASP.NET,async 关键字代码)的功能TransactionScope切换线程,但不会复制.

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

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

4

2 回答 2

1

是的。我敢肯定这在当时看起来是个好主意,但 [ThreadStatic] 让开发人员陷入一种虚假的安全感。ThreadStatic 字段具有全局变量的许多缺点,唯一的优点(不同的线程有自己的全局事物的实例)也有相应的缺点(如果切换线程,事物就会消失)。这不是一场胜利。全局变量很糟糕,线程静态全局变量和常规类型一样糟糕。

我在一个相当大的代码库上工作,几年前有几十个开发人员(如果你可以的话,可能有几百个在过去几年离开团队的人),并且 [ThreadStatic] 经常咬我们。我们有大量的代码,在幕后,使用 ThreadStatic 全局,如果你在工作线程上做任何事情,它当然会中断。就像我说的,我敢肯定这在当时看起来是个好主意……但现在我们付出的代价比它买给我们的要多得多。

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

于 2014-11-04T07:31:03.547 回答
1

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

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

所以你看,一个不能代替另一个。ThreadStatic是低级原语。我认为它的用例在CallContext等出现之后并没有减少。请注意,它的用例非常小——我想我最后一次使用它可能是在两年多以前。

我会将事情Transaction.Current描述为滥用 TLS。它从来都不是为此而设计的,所以当 TLS 似乎破坏异步时,这只是因为它一开始就不应该被用于此目的。

于 2014-11-04T07:57:53.057 回答