ThreadStatic V. s. ThreadLocal: является ли generic лучше, чем атрибут?
[ThreadStatic]
определяется с помощью атрибута while ThreadLocal<T>
использует generic.
Почему были выбраны различные дизайнерские решения?
Каковы преимущества и недостатки использования общих атрибутов в этом случае?
3 ответа:
что-то в блоге, отмеченном в комментариях, не делает явным, но я считаю, что это очень важно, это
[ThreadStatic]
не инициализирует автоматически вещи для каждого потока. Например, скажем, у вас есть это:[ThreadStatic] private static int Foo = 42;
первый поток, который использует этот
Foo
инициализации42
. Но последующих потоков не будет. Инициализатор работает только для первого потока. Поэтому вам придется написать код, чтобы проверить, инициализирован ли он.
ThreadLocal<T>
решает эту проблему, позволяя вам предоставить функцию инициализации (как показывает блог Рида), которая запускается до первого доступа к элементу.на мой взгляд, нет никакого преимущества в использовании
[ThreadStatic]
вместоThreadLocal<T>
.
ThreadStatic инициализировать только на первом потоке, ThreadLocal инициализировать для каждого потока. Ниже приведена простая демонстрация:
public static ThreadLocal<int> _threadlocal = new ThreadLocal<int>(() => { return Thread.CurrentThread.ManagedThreadId; }); public static void Main() { new Thread(() => { for (int x = 0; x < _threadlocal.Value; x++) { Console.WriteLine("First Thread: {0}", x); } }).Start(); new Thread(() => { for (int x = 0; x < _threadlocal.Value; x++) { Console.WriteLine("Second Thread: {0}", x); } }).Start(); Console.ReadKey(); }
основная идея ThreadStatic заключается в поддержании отдельная копия переменной для каждого потока.
class Program { [ThreadStatic] static int value = 10; static void Main(string[] args) { value = 25; Task t1 = Task.Run(() => { value++; Console.WriteLine("T1: " + value); }); Task t2 = Task.Run(() => { value++; Console.WriteLine("T2: " + value); }); Task t3 = Task.Run(() => { value++; Console.WriteLine("T3: " + value); }); Console.WriteLine("Main Thread : " + value); Task.WaitAll(t1, t2, t3); Console.ReadKey(); } }
В приведенном выше фрагменте, у нас есть отдельная копия
value
для каждого потока, включая основной поток.таким образом, переменная ThreadStatic будет инициализирована до значения по умолчанию для других потоков, кроме потока, на котором она создана.
Если мы хотим инициализируйте переменную в каждом потоке по-своему, используйте ThreadLocal.