Biar Aplikasi Gak Lemot Yuk Kita Bedah Bedanya Task dan Thread di C#

Share
Biar Aplikasi Gak Lemot Yuk Kita Bedah Bedanya Task dan Thread di C#
Photo by Asep S.Pd/Unsplash

Pernah gak sih kalian lagi asik scroll aplikasi terus tiba tiba layarnya macet total gara gara ada proses berat yang lagi jalan di belakang. Rasanya pasti menyebalkan banget apalagi kalau kita lagi butuh aplikasi itu buat kerja cepat. Nah masalah aplikasi yang lemot atau ngehang ini biasanya berawal dari cara kita mengelola proses di balik layar. Dalam dunia pemrograman C# ada dua jagoan yang sering disebut sebut buat urusan multitasking yaitu Task dan Thread. Banyak dari kita mungkin menganggap keduanya sama saja karena ujung ujungnya bikin kode jalan secara paralel. Tapi ternyata ada perbedaan mendasar yang kalau kita pahami bakal bikin performa aplikasi kita jadi jauh lebih asik dan responsif. Kita bakal bedah satu per satu mulai dari konsep dasar sampai kapan kita harus pilih salah satu di antara mereka supaya kode kita gak cuma jalan tapi juga efisien.

Kenalan Lebih Dekat Sama Thread Si Pekerja Manual

Kalau kita bayangkan sebuah aplikasi itu sebagai sebuah kantor maka Thread adalah pekerja fisik yang ada di sana. Setiap Thread punya meja sendiri punya peralatan sendiri dan tentu saja memakan ruang di kantor tersebut. Di dalam ekosistem C# sebuah Thread mewakili satu alur eksekusi yang sebenarnya di tingkat sistem operasi. Ketika kita membuat sebuah Thread baru artinya kita meminta sistem operasi untuk mengalokasikan sumber daya yang cukup besar. Bayangkan saja secara default satu Thread di lingkungan Windows bisa memakan memori sekitar satu megabyte hanya untuk tumpukan eksekusi atau stack. Kalau aplikasi kita cuma punya satu atau dua Thread mungkin gak masalah tapi bayangkan kalau kita sembarangan bikin ratusan Thread sekaligus. Komputer kita bakal keberatan beban karena harus mengelola semua pekerja manual ini secara bersamaan.

Thread ini sifatnya sangat mendasar dan memberikan kita kendali penuh atas apa yang terjadi. Kita bisa mengatur prioritasnya kita bisa menghentikannya secara paksa atau kita bisa membuat Thread tersebut berjalan terus menerus di latar belakang. Tapi di balik kekuatannya Thread punya sisi gelap yaitu biaya overhead yang tinggi. Proses berpindah dari satu Thread ke Thread lainnya atau yang biasa disebut context switching itu butuh tenaga CPU yang lumayan besar. Itulah kenapa kalau kita pakai Thread secara mentah tanpa perhitungan matang aplikasi kita bukannya makin cepat malah makin lemot gara gara CPU sibuk ngurusin manajemen pekerjanya daripada ngerjain tugas intinya.

Mengenal Task Si Manajemen Pintar Di Atas Thread

Nah sekarang mari kita bahas tentang Task yang hadir sebagai solusi lebih modern dan elegan. Kalau Thread tadi adalah pekerja fisiknya maka Task bisa kita ibaratkan sebagai daftar tugas atau job desk yang ingin diselesaikan. Task tidak selalu berarti membuat satu pekerja baru melainkan dia adalah sebuah janji bahwa suatu pekerjaan akan selesai di masa depan. Di balik layar Task sebenarnya berjalan di atas Thread juga tapi dia gak asal bikin Thread baru. Task menggunakan sesuatu yang namanya Thread Pool. Ini adalah sekumpulan Thread yang sudah disediakan oleh sistem dan siap pakai. Jadi daripada kita capek capek rekrut pekerja baru setiap ada tugas kita tinggal lempar tugas itu ke kumpulan pekerja yang sudah standby tadi.

Penggunaan Task ini bikin aplikasi kita jadi jauh lebih ringan karena proses pembuatan dan penghancuran Thread yang mahal itu bisa dihindari. Task jauh lebih asik karena dia sudah dibekali dengan fitur fitur modern seperti pengembalian nilai secara langsung. Kalau pakai Thread biasa kita sering bingung gimana caranya dapet hasil perhitungan dari Thread itu tanpa bikin variabel global yang ribet. Dengan Task kita cukup menunggu hasilnya lewat properti Result atau menggunakan kata kunci await yang sudah sangat populer di C#. Ini bikin kode kita terlihat lebih bersih dan lebih mudah dibaca seolah olah kodenya berjalan secara berurutan padahal sebenarnya dia lagi lari kencang di latar belakang.

Perbedaan Signifikan Antara Task Dan Thread

Ada beberapa poin krusial yang bikin kita harus sadar kenapa Task seringkali jadi pilihan utama dibanding Thread. Hal pertama yang paling terasa adalah penggunaan sumber daya memori. Seperti yang kita singgung tadi Thread itu boros karena setiap satu unitnya butuh alokasi memori yang tetap dan besar. Sementara Task jauh lebih efisien karena dia cuma sebuah objek kecil di memori yang memberikan instruksi pada Thread Pool. Kita bisa punya ribuan Task yang antre buat dikerjakan tanpa bikin memori komputer kita langsung penuh. Ini adalah kunci utama kalau kita mau bikin aplikasi skala besar yang melayani banyak pengguna sekaligus.

Hal kedua adalah soal fleksibilitas dalam pengelolaan alur kerja. Task punya fitur keren bernama chaining atau perantaian tugas. Kita bisa dengan mudah bilang kalau tugas A selesai tolong lanjutin ke tugas B lalu kalau ada error tolong lari ke tugas C. Kalau kita pakai Thread manual melakukan hal seperti ini bakal butuh logika yang sangat rumit dan rawan bug. Selain itu Task juga mendukung pembatalan pekerjaan lewat CancellationToken yang sangat rapi. Jadi kalau user tiba tiba membatalkan pencarian kita bisa langsung stop semua proses Task tersebut tanpa harus membunuh Thread secara kasar yang bisa bikin aplikasi kita crash.

Kapan Saat Yang Tepat Buat Pakai Thread

Meskipun Task terlihat sangat superior bukan berarti Thread sudah gak berguna lagi. Ada beberapa kondisi khusus di mana kita butuh kekuatan murni dari sebuah Thread. Misalnya ketika kita punya pekerjaan yang durasinya sangat lama atau long running task yang gak boleh terputus sama sekali. Kalau kita pakai Task buat kerjaan yang jalannya berjam jam atau bahkan selama aplikasi hidup kita bisa saja memenuhi antrean di Thread Pool dan menghalangi tugas tugas kecil lainnya buat jalan. Dalam kasus seperti ini bikin satu Thread khusus yang didedikasikan buat tugas berat tersebut adalah pilihan yang bijak.

Thread juga masih asik dipakai kalau kita butuh kontrol tingkat rendah yang sangat spesifik terhadap perilaku sistem operasi. Misalnya kalau kita lagi bikin driver atau aplikasi yang butuh sinkronisasi perangkat keras yang sangat ketat. Di sana kita mungkin butuh mengatur Thread Priority ke tingkat paling tinggi supaya tidak diganggu oleh proses lain. Tapi buat sebagian besar aplikasi bisnis aplikasi mobile atau web yang kita kembangkan sehari hari kebutuhan seperti ini jarang banget muncul. Jadi kalau kalian gak punya alasan yang sangat kuat buat kontrol manual sebaiknya hindari bikin Thread sendiri secara langsung.

Memaksimalkan Performa Dengan Async Dan Await

Salah satu alasan kenapa Task jadi primadona adalah karena dia jodoh sejatinya async dan await. Fitur ini beneran mengubah cara kita menulis kode asinkron di C#. Dulu sebelum ada ini kita sering terjebak dalam callback hell yang bikin pusing tujuh keliling. Dengan Task kita bisa menulis kode yang keliatannya seperti kode sinkron biasa tapi sebenarnya gak ngeblokir thread utama. Ini penting banget buat aplikasi desktop seperti WPF atau WinForms serta aplikasi mobile seperti MAUI. Kalau kita jalankan proses ambil data dari internet di thread utama maka UI aplikasi bakal macet sampai data itu datang.

Dengan menggunakan Task yang digabung dengan await aplikasi kita bakal tetep asik digeser geser tombolnya tetep bisa diklik meskipun di belakang sana dia lagi sibuk download data puluhan megabyte. Begitu datanya siap si Task bakal ngasih tahu aplikasi buat nampilin hasilnya. Yang lebih keren lagi sistem bakal membebaskan thread yang lagi nunggu itu buat ngerjain hal lain sementara proses I/O atau input output lagi jalan. Ini namanya non blocking I/O dan ini rahasia kenapa server yang pakai Task bisa menangani ribuan permintaan secara bersamaan dengan penggunaan CPU yang tetap rendah.

Tips Menghindari Jebakan Batman Dalam Multitasking

Belajar multitasking itu asik tapi juga banyak jebakan yang bisa bikin pusing. Salah satu masalah yang paling sering muncul adalah Race Condition. Ini terjadi kalau ada dua Task atau Thread yang mencoba mengubah satu data yang sama di waktu yang bersamaan. Hasilnya bisa berantakan dan sulit ditebak. Solusinya kita harus pakai mekanisme penguncian atau locking tapi jangan sembarangan juga karena bisa berujung pada Deadlock. Deadlock itu kondisi di mana Task A nunggu Task B selesai tapi Task B juga nunggu Task A selesai akhirnya mereka berdua diam selamanya dan aplikasi kita jadi hang.

Kita juga harus hati hati saat menggunakan Task.Result secara sinkron. Banyak programmer pemula yang panggil .Result di tengah kode biasa dan ini sering banget bikin Deadlock terutama di aplikasi yang punya Synchronization Context seperti aplikasi UI. Selalu usahakan pakai await sampai ke level paling atas supaya alur datanya tetap asik dan lancar. Selain itu jangan lupa buat selalu menangani error di dalam Task. Kalau Thread melempar error dan gak ditangkap biasanya aplikasi langsung tutup paksa. Kalau Task dia bakal menyimpan error itu dan baru akan dilempar saat kita melakukan await. Ini lebih aman tapi kita harus tetap waspada jangan sampai ada error yang tertelan tanpa kita sadari.

Kesimpulan Dan Langkah Selanjutnya Buat Kita

Dunia multithreading di C# memang luas banget tapi dengan memahami bedanya Task dan Thread kita sudah punya fondasi yang kuat buat bikin aplikasi yang kencang. Secara garis besar pakailah Task untuk hampir semua kebutuhan kalian karena dia lebih ringan lebih pintar dan lebih mudah dikelola. Gunakan Thread hanya jika kalian benar benar butuh kendali manual atau punya proses yang berjalan sangat lama dan tidak ingin mengganggu Thread Pool. Dengan pendekatan yang tepat aplikasi kita gak bakal lagi dibilang lemot sama user.

Sekarang cobalah lihat kembali kode yang pernah kalian tulis. Apakah masih banyak penggunaan Thread secara manual yang sebenarnya bisa diganti jadi Task. Atau mungkin ada proses berat yang masih jalan di thread utama sehingga bikin UI macet. Mulailah bermigrasi ke pola async await dan rasakan sendiri betapa asik pengembangan aplikasi kalau kita sudah paham cara mainnya. Semangat terus belajarnya dan jangan takut buat eksperimen karena cara terbaik buat paham ya dengan langsung praktek di proyek nyata kalian masing masing.

Read more