2013-07-23 3 views
4

[ThreadStatic] используется в разных местах среды .NET для обеспечения контекста окружающего пространства для различных функций (например, Transaction.Current, который используется для TransactionScope).Является ли использование ThreadStatic в коде .NET Framework вредной реликвией временного возраста?

К сожалению, это означает, что функции, которые выполняют некоторые манипуляции с потоком (ASP.NET, код ключа async), переключают потоки, но не копируют 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

... получить ссылку на чтение только для среды, в которой они были вызваны; если методы async должны передавать данные в дополнительные вложенные методы, они могут построить новую среду со ссылкой на родителя. – supercat

ответ

1

В действительности они имеют очень разные варианты использования.

  • ThreadStatic не может передавать значение поперек переключения контекста await или аналогичный.
  • CallContext не может сохранить значение для каждой нити.

Итак, вы видите, нельзя заменить другого. ThreadStatic - примитив низкого уровня. Я не думаю, что его случаи использования стали меньше после того, как CallContext и т. Д. Пришли. Обратите внимание, что его варианты использования : исчезающе мало - я думаю, что в прошлый раз, когда я использовал его, возможно, было более двух лет назад.

Я бы охарактеризовал такие вещи, как Transaction.Current как злоупотребление TLS. Это никогда не предназначалось для этого, и поэтому, когда TLS, похоже, нарушало асинхронность, это было только потому, что никогда не использовалось для этого в первую очередь.

1

Да. Я уверен, что в то время это казалось хорошей идеей, но [ThreadStatic] убаюкивает разработчиков в ложном смысле безопасности. Поля ThreadStatic имеют множество недостатков глобальных переменных, и единственное преимущество (разные потоки имеют свои собственные экземпляры глобальной вещи) имеет соответствующий недостаток (эта вещь исчезает, если вы переключаете потоки). Это не выигрыш. Глобалы сосут, а поточно-статические глобалы всасывают каждый бит так же, как и обычный.

Я работаю над довольно большой базой кода, несколько лет с десятками разработчиков (возможно, пару сотен, если бы вы могли покинуть команду за последние несколько лет), а [ThreadStatic] укусит нас на регулярной основа. У нас есть тонны кода, который под крышкой использует глобальный ThreadStatic, который, разумеется, ломается, если вы что-то делаете в рабочем потоке. Как я уже сказал, я уверен, что в то время это казалось хорошей идеей ... но теперь это стоило нам гораздо больше, чем когда-либо покупал нас.

Альтернативой может быть передача одного и того же объекта (HttpContext, Transaction и т. Д.) Для каждого метода, который зависит от него. Это требует большего набора текста, но, по моему не очень скромному мнению, в конечном итоге все еще лучше.

Смежные вопросы