Saya ingin memicu tugas untuk dijalankan di thread latar belakang. Saya tidak ingin menunggu tugas selesai.
Dalam .net 3.5 saya akan melakukan ini:
ThreadPool.QueueUserWorkItem(d => { DoSomething(); });
Dalam .net 4 TPL adalah cara yang disarankan. Pola umum yang saya lihat direkomendasikan adalah:
Task.Factory.StartNew(() => { DoSomething(); });
Namun, StartNew()
metode tersebut mengembalikan Task
objek yang diimplementasikan IDisposable
. Hal ini tampaknya diabaikan oleh orang-orang yang merekomendasikan pola ini. Dokumentasi MSDN tentang Task.Dispose()
metode tersebut mengatakan:
"Selalu hubungi Buang sebelum Anda merilis referensi terakhir Anda ke Tugas."
Anda tidak dapat memanggil buang pada tugas hingga selesai, jadi meminta utas utama menunggu dan memanggil buang akan menggagalkan tujuan melakukan pada utas latar belakang sejak awal. Tampaknya juga tidak ada acara selesai / selesai yang dapat digunakan untuk pembersihan.
Halaman MSDN di kelas Tugas tidak mengomentari hal ini, dan buku "Pro C # 2010 ..." merekomendasikan pola yang sama dan tidak memberikan komentar tentang pembuangan tugas.
Saya tahu jika saya membiarkannya, finalizer akan menangkapnya pada akhirnya, tetapi apakah ini akan kembali dan menggigit saya ketika saya melakukan banyak tugas & melupakan tugas seperti ini dan thread finalizer menjadi kewalahan?
Jadi pertanyaan saya adalah:
- Apakah dapat diterima untuk tidak memanggil
Dispose()
padaTask
kelas dalam kasus ini? Dan jika ya, mengapa dan apakah ada risiko / konsekuensi? - Apakah ada dokumentasi yang membahas hal ini?
- Atau adakah cara yang tepat untuk membuang
Task
objek yang saya lewatkan? - Atau adakah cara lain untuk melakukan tugaskan & lupakan tugas dengan TPL?
sumber
Jawaban:
Ada diskusi tentang ini di forum MSDN .
Stephen Toub, anggota tim Microsoft pfx mengatakan ini:
Pembaruan (Okt 2012)
Stephen Toub telah memposting blog berjudul Do I need to membuang Tasks? yang memberikan beberapa detail lebih lanjut, dan menjelaskan peningkatan dalam .Net 4.5.
Singkatnya: Anda tidak perlu
Task
99% membuang objek setiap saat.Ada dua alasan utama untuk membuang objek: untuk membebaskan sumber daya yang tidak terkelola secara tepat waktu, cara deterministik, dan untuk menghindari biaya menjalankan finalizer objek. Tak satu pun dari ini berlaku untuk
Task
sebagian besar waktu:Task
mengalokasikan gagang tunggu internal (satu-satunya sumber daya yang tidak dikelola dalamTask
objek) adalah saat Anda secara eksplisit menggunakanIAsyncResult.AsyncWaitHandle
dariTask
, danTask
obyek itu sendiri tidak memiliki finalizer; pegangan itu sendiri dibungkus dalam sebuah objek dengan finalizer, jadi kecuali dialokasikan, tidak ada finalizer untuk dijalankan.sumber
EndInvoke
di WinForms saat menggunakanBeginInvoke
untuk menjalankan kode pada utas UI). (2) Stephen Toub cukup dikenal sebagai pembicara reguler tentang penggunaan PFX yang efektif (misalnya di channel9.msdn.com ), jadi jika ada yang bisa memberikan panduan yang baik maka dia itu. Perhatikan paragraf keduanya: ada kalanya menyerahkan hal-hal kepada finalis lebih baik.Ini adalah jenis masalah yang sama dengan kelas Thread. Ini mengkonsumsi 5 sistem operasi menangani tetapi tidak mengimplementasikan IDisposable. Keputusan bagus dari desainer asli, tentu saja ada beberapa cara yang masuk akal untuk memanggil metode Dispose (). Anda harus menelepon Gabung () terlebih dahulu.
Kelas Tugas menambahkan satu pegangan untuk ini, acara reset manual internal. Sumber daya sistem operasi mana yang termurah. Tentu saja, metode Dispose () hanya dapat merilis satu penanganan kejadian itu, bukan 5 pegangan yang dikonsumsi Thread. Ya, jangan repot-repot .
Berhati-hatilah karena Anda harus tertarik dengan properti IsFaulted tugas. Ini adalah topik yang cukup jelek, Anda dapat membaca lebih lanjut tentang itu di artikel Perpustakaan MSDN ini . Setelah Anda menangani ini dengan benar, Anda juga harus memiliki tempat yang bagus di kode Anda untuk membuang tugas.
sumber
Thread
dalam banyak kasus, itu menggunakan ThreadPool.Saya ingin melihat seseorang mempertimbangkan teknik yang ditunjukkan dalam posting ini: Pemanggilan delegasi asynchronous yang aman dan lupakan tipe aman di C #
Sepertinya metode ekstensi sederhana akan menangani semua kasus sepele dari interaksi dengan tugas dan dapat memanggil buang di atasnya.
sumber
Task
contoh yang dikembalikan olehContinueWith
, tetapi lihat kutipan dari Stephen Toub adalah jawaban yang diterima: tidak ada yang dibuang jika tidak ada yang melakukan penantian pemblokiran pada suatu tugas.Task disper = null; disper = tsk.ContinueWith(cnt => { cnt.Dispose(); disper.Dispose(); });