Saya melihat banyak orang di posting blog dan di sini di SO menghindari atau menasihati penggunaan Thread
kelas dalam versi terbaru C # (dan maksud saya tentu saja 4.0+, dengan tambahan Task
& teman). Bahkan sebelumnya, ada perdebatan tentang fakta bahwa fungsi thread lama yang biasa dapat diganti dalam banyak kasus oleh ThreadPool
kelas.
Juga, mekanisme khusus lainnya selanjutnya membuat Thread
kelas menjadi kurang menarik, seperti Timer
mengganti combo Thread
+ jelek Sleep
, sedangkan untuk GUI yang kami miliki BackgroundWorker
, dll.
Namun, Thread
tampaknya tetap menjadi konsep yang sangat akrab bagi sebagian orang (termasuk saya), orang-orang yang, ketika dihadapkan dengan tugas yang melibatkan beberapa jenis eksekusi paralel, langsung melompat menggunakan Thread
kelas lama yang baik . Akhir-akhir ini saya bertanya-tanya apakah sudah waktunya untuk mengubah cara saya.
Jadi pertanyaan saya adalah, apakah ada kasus ketika perlu atau berguna untuk menggunakan Thread
objek lama biasa daripada salah satu konstruksi di atas?
sumber
64.5k
.Jawaban:
Kelas Thread tidak dapat dibuat usang karena jelas ini adalah detail implementasi dari semua pola lain yang Anda sebutkan.
Tapi itu bukan pertanyaan Anda; pertanyaan Anda adalah
Tentu. Tepatnya pada kasus-kasus di mana salah satu konstruksi tingkat yang lebih tinggi tidak memenuhi kebutuhan Anda.
Saran saya adalah jika Anda berada dalam situasi di mana alat abstraksi tinggi yang ada tidak memenuhi kebutuhan Anda, dan Anda ingin menerapkan solusi menggunakan utas, maka Anda harus mengidentifikasi abstraksi yang hilang yang benar-benar Anda butuhkan , dan kemudian menerapkan abstraksi itu menggunakan utas , lalu gunakan abstraksi .
sumber
Utas adalah blok bangunan dasar untuk hal-hal tertentu (yaitu paralelisme dan asinkron) dan karenanya tidak boleh disingkirkan. Namun , bagi kebanyakan orang dan sebagian besar kasus penggunaan, ada hal-hal yang lebih tepat untuk digunakan yang Anda sebutkan, seperti kumpulan utas (yang menyediakan cara yang bagus untuk menangani banyak pekerjaan kecil secara paralel tanpa membebani mesin dengan menghasilkan 2000 utas sekaligus),
BackgroundWorker
( yang merangkum acara yang berguna untuk satu karya yang berumur pendek).Tetapi hanya karena dalam banyak kasus itu lebih tepat karena mereka melindungi programmer dari menciptakan kembali roda yang tidak perlu, melakukan kesalahan bodoh dan sejenisnya, itu tidak berarti bahwa kelas Thread sudah usang. Ini masih digunakan oleh abstraksi yang disebutkan di atas dan Anda masih akan membutuhkannya jika Anda memerlukan kontrol yang lebih cermat atas utas yang tidak tercakup oleh kelas yang lebih khusus.
Dalam nada yang sama,
.NET
tidak melarang penggunaan array, meskipunList<T>
lebih cocok untuk banyak kasus di mana orang menggunakan array. Hanya karena Anda mungkin masih ingin membuat hal-hal yang tidak tercakup oleh lib standar.sumber
Task
danThread
abstraksi yang berbeda. Jika Anda ingin membuat model utas,Thread
kelas masih merupakan pilihan yang paling tepat. Misalnya jika Anda perlu berinteraksi dengan utas saat ini, saya tidak melihat jenis yang lebih baik untuk ini.Namun, seperti yang Anda tunjukkan. NET telah menambahkan beberapa abstraksi khusus yang lebih disukai
Thread
dalam banyak kasus.sumber
The
Thread
kelas tidak usang, masih berguna dalam keadaan khusus.Di mana saya bekerja, kami menulis 'prosesor latar belakang' sebagai bagian dari sistem manajemen konten: layanan Windows yang memantau direktori, alamat email, dan umpan RSS, dan setiap kali sesuatu yang baru muncul, jalankan tugas di atasnya - biasanya untuk mengimpor data.
Upaya untuk menggunakan kumpulan thread untuk ini tidak berhasil: ia mencoba mengeksekusi terlalu banyak hal pada saat yang sama dan membuang disk, jadi kami menerapkan sistem polling dan eksekusi kami sendiri menggunakan
Thread
kelas secara langsung .sumber
Opsi baru membuat penggunaan langsung dan pengelolaan utas (mahal) lebih jarang.
Yang merupakan cara yang sangat mahal dan relatif rumit untuk melakukan sesuatu secara paralel.
Perhatikan bahwa biaya paling penting: Anda tidak dapat menggunakan utas lengkap untuk melakukan pekerjaan kecil, itu akan menjadi kontraproduktif. ThreadPool memerangi biaya, kelas Tugas, kerumitan (pengecualian, menunggu dan membatalkan).
sumber
Untuk menjawab pertanyaan " adakah kasus ketika perlu atau berguna untuk menggunakan objek Thread lama biasa ", saya akan mengatakan Thread lama biasa berguna (tetapi tidak perlu) ketika Anda memiliki proses yang berjalan lama yang Anda menangkan ' t pernah berinteraksi dengan dari utas yang berbeda.
Misalnya, jika Anda menulis aplikasi yang berlangganan untuk menerima pesan dari semacam antrian pesan dan aplikasi Anda akan melakukan lebih dari sekadar memproses pesan-pesan itu, maka akan berguna untuk menggunakan Thread karena utasnya akan mandiri (yaitu Anda tidak menunggu untuk diselesaikan), dan itu tidak berumur pendek. Menggunakan kelas ThreadPool lebih untuk mengantri sekumpulan item pekerjaan berumur pendek dan memungkinkan kelas ThreadPool mengelola secara efisien memproses masing-masing saat Thread baru tersedia. Tasks dapat digunakan di mana Anda akan menggunakan Thread secara langsung, tetapi dalam skenario di atas, saya rasa mereka tidak akan membeli banyak untuk Anda. Mereka membantu Anda berinteraksi dengan utas lebih mudah (yang skenario di atas tidak
sumber
System.IO.Threading.Thread
.Mungkin bukan jawaban yang Anda harapkan, tetapi saya menggunakan Thread sepanjang waktu saat melakukan pengkodean terhadap .NET Micro Framework. MF cukup dikurangi dan tidak menyertakan abstraksi tingkat yang lebih tinggi dan kelas Thread sangat fleksibel saat Anda perlu mendapatkan kinerja terakhir dari CPU MHz rendah.
sumber
Anda dapat membandingkan kelas Thread dengan ADO.NET. Ini bukan alat yang disarankan untuk menyelesaikan pekerjaan, tetapi tidak usang. Alat lain dibangun di atasnya untuk memudahkan pekerjaan.
Tidak salah untuk menggunakan kelas Thread di atas hal-hal lain, terutama jika hal-hal itu tidak menyediakan fungsionalitas yang Anda butuhkan.
sumber
Itu belum pasti usang.
Masalah dengan aplikasi multithread adalah bahwa mereka sangat sulit untuk dilakukan dengan benar (seringkali perilaku tak tentu, input, output dan juga keadaan internal itu penting), jadi seorang programmer harus mendorong pekerjaan sebanyak mungkin ke kerangka / alat. Abstraksi itu. Namun, musuh bebuyutan abstraksi adalah kinerja.
Saya akan menggunakan Thread dan kunci hanya jika akan ada masalah kinerja yang serius, sasaran kinerja tinggi.
sumber
Saya selalu menggunakan kelas Thread ketika saya perlu menghitung dan mengontrol thread yang telah saya putar. Saya menyadari bahwa saya dapat menggunakan threadpool untuk menampung semua pekerjaan saya yang luar biasa, tetapi saya tidak pernah menemukan cara yang baik untuk melacak berapa banyak pekerjaan yang sedang dilakukan atau apa statusnya.
Sebagai gantinya, saya membuat koleksi dan menempatkan utas di dalamnya setelah saya memutarnya - hal terakhir yang dilakukan utas adalah menghapus dirinya sendiri dari koleksi. Dengan begitu, saya selalu dapat mengetahui berapa banyak utas yang berjalan, dan saya dapat menggunakan koleksi tersebut untuk menanyakan apa yang dilakukannya. Jika ada kasus ketika saya perlu membunuh mereka semua, biasanya Anda harus menyetel semacam tanda "Batalkan" di aplikasi Anda, tunggu setiap utas memperhatikannya sendiri dan berhenti sendiri - dalam kasus saya, saya dapat menjalankan koleksi dan mengeluarkan Thread.Abort ke masing-masing secara bergantian.
Dalam hal ini, saya belum menemukan cara yang lebih baik untuk bekerja secara langsung dengan kelas Thread. Seperti yang disebutkan Eric Lippert, yang lainnya hanyalah abstraksi tingkat yang lebih tinggi, dan cocok untuk bekerja dengan kelas tingkat yang lebih rendah ketika penerapan tingkat tinggi yang tersedia tidak memenuhi kebutuhan Anda. Sama seperti Anda terkadang perlu melakukan panggilan Win32 API ketika .NET tidak memenuhi kebutuhan Anda secara tepat, akan selalu ada kasus di mana kelas Thread adalah pilihan terbaik meskipun ada "kemajuan" baru-baru ini.
sumber