ThreadStatic vs ThreadLocal <T>: apakah generik lebih baik daripada atribut?

95

[ThreadStatic]didefinisikan menggunakan atribut sementara ThreadLocal<T>menggunakan generik. Mengapa solusi desain yang berbeda dipilih? Apa keuntungan dan kerugian menggunakan atribut generik over dalam kasus ini?

pengguna2341923
sumber
4
Lihat reedcopsey.com/2009/11/12/… - Saya tidak melihat apa hubungannya ini dengan refleksi ...
Jon Skeet

Jawaban:

112

Sesuatu yang dicatat oleh posting blog di komentar tidak membuatnya eksplisit, tetapi menurut saya sangat penting, adalah itu [ThreadStatic]tidak secara otomatis menginisialisasi hal-hal untuk setiap utas. Misalnya, Anda memiliki ini:

[ThreadStatic]
private static int Foo = 42;

Utas pertama yang menggunakan ini akan melihat Foodiinisialisasi ke 42. Tetapi utas berikutnya tidak akan. Penginisialisasi hanya berfungsi untuk utas pertama. Jadi Anda akhirnya harus menulis kode untuk memeriksa apakah sudah diinisialisasi.

ThreadLocal<T> memecahkan masalah itu dengan membiarkan Anda menyediakan fungsi inisialisasi (seperti yang ditunjukkan blog Reed) yang dijalankan sebelum pertama kali item tersebut diakses.

Menurut pendapat saya, tidak ada keuntungan menggunakan [ThreadStatic]daripada ThreadLocal<T>.

Jim Mischel
sumber
20
Kecuali mungkin yang ThreadLocal<T>tersedia di NET 4 dan atas, dan yang ThreadStaticatribut juga tersedia dalam 3.5 dan bawah.
Jeroen
2
Dan jika Anda tidak menggunakan penginisialisasi untuk menyetel nilainya, tetapi malah menyetelnya di beberapa titik setelah inisialisasi, menggunakan [ThreadStatic] lebih bersih secara sintaksis.
Pikir
9
Dan kecuali yang ThreadLocal<T>menerapkan IDisposabledan biasanya memaksa Anda untuk menerapkan IDisposablejuga, yang memaksa penelepon Anda untuk membuang Anda dan karena itu menerapkannya IDisposablejuga ...
Stefan Steinegger
4
@StefanSteinegger: Saya akan sangat berhati-hati menggunakan ThreadLocalatau ThreadStaticdengan utas kumpulan. Nilai-nilai tersebut akan tetap ada sepanjang masa pakai utas kumpulan, tidak hanya untuk tugas yang Anda tetapkan. Itu dapat menyebabkan masalah bagi Anda dalam beberapa cara yang tidak terlalu jelas. Lihat stackoverflow.com/questions/561518/… dan pertanyaan serupa untuk info lebih lanjut.
Jim Mischel
3
Bukankah bidang dalam contoh juga harus dideklarasikan static? Lihat msdn.microsoft.com/en-us/library/…
entheh
39

ThreadStatic Inisialisasi hanya pada utas pertama, ThreadLocal Inisialisasi untuk setiap utas. Di bawah ini adalah demonstrasi sederhana:

    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();
    }

masukkan deskripsi gambar di sini

marai
sumber
15

Ide utama di balik ThreadStatic adalah mempertahankan salinan variabel terpisah untuk setiap utas .

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();
        }
    }

Dalam cuplikan di atas, kami memiliki salinan terpisah valueuntuk setiap utas, termasuk utas utama.

masukkan deskripsi gambar di sini

Jadi, variabel ThreadStatic akan diinisialisasi ke nilai defaultnya di utas lain kecuali utas tempat ia dibuat.

Jika kita ingin menginisialisasi variabel pada setiap utas dengan cara kita sendiri, gunakan ThreadLocal.

Sanjeev
sumber
1
Dan artikel lengkapnya bisa dilihat disini .
Daniel Dušek