Threading .NET 1: Multi Threading Intro
Selain ORM, gw juga mau memulai pembahasan mengenai Multi Threading di .NET. Banyak sekali teknik Multi Threading yang bisa dipakai di .NET. Kebetulan gw pernah menyentuh hampir semua teknik yang ada. Melalui seri postingan ini, gw ingin mencoba membagi ilmu yang gw dapatkan selama bermain-main dengan multi-threading di .NET Framework. Pada seri pertama, gw ingin membahas tentang Multi Threading sesuai pemahaman gw dan dalam bahasa gw sendiri 🙂
Sebagai overview, multi threading adalah melakukan dua pekerjaan secara konkuren atau paralel. Konkurensi di sini bisa berarti real-concurrency maupun pseudo-concurrency. Real-concurrency adalah konkurensi di mana dua atau lebih pekerjaan benar-benar dieksekusi secara bersamaan pada dua atau lebih prosesor yang berbeda. Patut diingat bahwa satu prosesor hanya dapat mengerjakan satu pekerjaan saja. Pada prosesor-prosesor multi-core atau hyper-threading, satu prosesor mengandung lebih dari satu inti prosesor sehingga dapat mengerjakan lebih dari satu pekerjaan pada saat yang bersamaan.
Sedangkan pseudo-concurrency adalah dua atau lebih pekerjaan yang seolah-olah dikerjakan secara konkuren atau paralel padahal pada kenyataannya pekerjaan-pekerjaan tersebut dikerjakan secara bergantian oleh prosesor. Namun karena kecepatan yang dimiliki oleh prosesor, pekerjaan-pekerjaan tersebut seolah-olah dikerjakan secara paralel.
Di kondisi pada umumnya, tidak ada sistem operasi yang menerapkan 100% real-concurrency (Kecuali untuk RTOS – Real Time Operating System). Sistem operasi mengatur penjadwalan setiap pekerjaan untuk dieksekusi oleh prosesor. Suatu pekerjaan dapat menempati prosesor dalam batas waktu tertentu. Setelah melebihi batas waktu tertentu, sistem operasi menghentikan sementara eksekusi dari pekerjaan tersebut, kemudian memberikan giliran kepada pekerjaan lain untuk dieksekusi. Ini dikarenakan pekerjaan yang harus dikerjakan oleh sistem operasi tidak hanya satu atau mungkin empat, sebanyak jumlah core pada Intel Core i5, melainkan ratusan, bahkan mencapai ribuan.
Setiap pekerjaan sebenarnya tidak perlu diselesaikan secepat mungkin. Sistem operasi hanya perlu memastikan throughput dari pekerjaan itu acceptable oleh pengguna dari komputer. Sebagai contoh, untuk menampilkan gambar pada monitor, komputer hanya perlu menampilkan 60 gambar per detik (fps). Sehingga sistem operasi hanya perlu memastikan bahwa pekerjaan penggambaran layar harus dikerjakan minimal 60 kali setiap detiknya, atau satu kali penggambaran diselesaikan selama 16 ms. Padahal bisa saja proses penggambaran hanya menggunakan kurang dari 16 ms, misalnya 1 ms. Oleh karena itu, 15 ms lainnya dapat diberikan kepada pekerjaan lainnya.
Selain itu, sistem operasi juga harus memastikan bahwa prosesor digunakan seefisien mungkin. Sistem komputer sendiri sebenarnya tidak synchronous. Setiap device (prosesor, memori, graphic card, bus, hard disk, dll) memiliki kecepatannya masing-masing dan bekerja sesuai dengan kecepatan tersebut. Kecepatan memori tidak secepat kecepatan prosesor. Jalur yang menghubungkan prosesor dengan periferal lainnya juga tidak secepat jalur yang menghubungkan prosesor dan memori. Apalagi hard disk merupakan perangkat yang paling lambat di dalam komputer.
Apabila sistem operasi tidak menjadwalkan berdasarkan faktor kecepatan periferal-periferal tersebut, maka banyak waktu disia-siakan oleh prosesor yang semestinya dapat digunakan oleh pekerjaan lainnya. Oleh karena itu, sistem operasi akan melakukan penjadwalan pekerjaan tersebut juga berdasarkan proses I/O (Input dan Output) yang dilakukan oleh pekerjaan tersebut. Sebagai contoh, misalnya suatu pekerjaan membutuhkan data dari hard disk. Lama waktu yang dibutuhkan hard disk untuk menyediakan data tersebut misalkan 5 ms. Setelah prosesor mengeksekusi intstruksi untuk meminta data ke hard disk, sistem operasi langsung menghentikan pekerjaan tersebut karena pekerjaan tersebut masih menunggu data agar tersedia untuk pekerjaan tersebut. Sehingga lama waktu 5 ms tersebut dapat digunakan oleh pekerjaan lainnya untuk dikerjakan di prosesor.
Sehingga jika di wrap-up, penjadwalan pekerjaan tersebut dipengaruhi tiga faktor utama:
- Lama pekerjaan tersebut dieksekusi di prosesor.
- Throughput yang diharapkan dari pekerjaan tersebut.
- Input dan Output yang dilakukan oleh pekerjaan tersebut.
Selanjutnya gw akan mendefinisikan pekerjaan di komputer sebagai thread. Thread adalah “benang kehidupan” dari pekerjaan yang dilakukan di komputer. Setiap program yang kita buat minimal memiliki satu thread. Thread tersebut akan dieksekusi oleh prosesor dan dikelola oleh sistem operasi sesuai penjabaran yang sudah diberikan di atas. Pada program kita, kita melakukan operasi menerima input dari pengguna, melakukan proses yang diminta oleh pengguna, kemudian menghasilkan output yang dapat dilihat oleh pengguna.
Pada program yang menggunakan GUI (Graphical User Interface), alur pekerjaan yang dilakukan oleh program tersebut adalah (sebenarnya program non-GUI juga melakukan proses yang sama):
Semua pekerjaan dilakukan secara berurutan. Sehingga yang jadi masalah adalah bagaimana jika proses melakukan pekerjaan berdasarkan input dari pengguna memakan waktu yang sangat lama sehingga proses menggambar GUI ke layar menjadi terhalang. Sebelumnya gw sudah menyebutkan bahwa komputer berusaha menampilkan gambar ke layar sebanyak 60 gambar per detik. Sehingga jika suatu program gagal mengikuti ketentuan tersebut, maka pengguna akan mulai melihat bahwa program berjalan lambat dan program tidak merespon apa yang pengguna ingin lakukan dengan program kita.
Kalau kalian menggunakan program, contohnya di OS Windows, kalau warna window sudah mulai washed out, kursor berputar-putar doang, kemudian di-klik layarnya keluar tulisan Not Responding, itu tandanya program itu terhalang untuk melakukan proses menggambar GUI dan menerima input gara-gara terdapat suatu pekerjaan yang dikerjakan namun tidak kunjung selesai. Pada saat itu pasti kita sudah kesal, mulai marah, bahkan sampai membanting komputer (lebay :P).
Nah oleh karena itu, pekerjaan-pekerjaan yang memakan waktu lama itu bisa kita pindahkan ke thread lainnya. Sehingga ketika pekerjaan itu dilakukan, pekerjaan itu tidak mengganggu proses yang harus dilakukan oleh thread utama, yaitu menggambar GUI ke layar dan menerima input dari user. Pembagian jadwal thread mana yang akan diekseksui terlebih dahulu dilakukan dan dikontrol sepenuhnya oleh sistem operasi, dan kita tidak perlu pusing-pusing memikirkan masalah tersebut. Sangat simpel.
Dengan menggunakan thread, kita juga dapat memaksimalkan sumber daya yang kita miliki, misalnya prosesor multi-core. Karena satu thread hanya dapat menempati satu core saja. Dengan melakukan pekerjaan pada lebih dari satu thread, maka pekerjaan tersebut dapat dikerjakan secara benar-benar paralel di core lainnya, dan melipat-gandakan throughput dari program kita. Misalnya kita punya program yang melakukan penjumlahan matriks persegi berukuran satu juta. Misalnya kita membutuhkan 100 detik untuk mengolah penjumlahan matriks tersebut dengan menggunakan satu thread saja, dengan memecah penjumlahan tersebut ke 4 thread di prosesor dengan 4 core, maka penjumlahan dapat dipercepat hingga maksimal 25 detik saja.
Pada seri-seri berikutnya, gw bakal menjelaskan bagaimana melakukan multi-threading di .NET Framework. Stay tuned!
Nice article kak. Ijin bookmark buat cemilan habis UAS.
Ditunggu seri berikutnya. 😀
Thank you. 😀
Sumpah!
This is all what I need for my bachelor thesis’s defense.
Tapi Gil, buat program yang menggunakan GUI, apakah mungkin untuk membuat lebih dari satu thread buat ngurusin penggambaran GUI ke layar (yang tadinya cuma diurusin sama satu thread, i.e. thread utama)?
Sampai saat ini, program TA gue cuma make dua thread – Thread utama dan thread buat “nungguin” data yang masuk/keluar port serial (COM). Masalahnya, begitu ada data yang masuk/keluar port serial, program gue yang ngegunain tidak kurang dari 100 komponen Windows Forms tsb (10 diantaranya menggunakan data binding ke DB), seringkali merasakan efek BANTING KOMPUTER yang lo jelasin di atas. (lebay)
Ditunggu seri buat skenario ini. ✗e✗
Ga bisa lebih dari satu thread yang ngurusin GUI. Karena lifeline dari GUI memang hanya di thread utama dari program kita. Kita hanya bisa “melempar” pekerjaan yang tidak berhubungan dengan GUI ke thread lain. Bahkan kalau dari thread lain, kita tidak bisa mengakses objek-objek GUI dan akses ke sana harus di-serialisasikan. Tekniknya mungkin lo udah tau tapi nanti di seri-seri selanjutnya bakal gw bahas.
Jika misalnya GUI tau-tau melambat karena setelah data datang, mungkin program lo kebanyakan melakukan serialisasi dari thread luar ke thread GUI lo sehingga jadinya pada intinya program lo tetep kebanyakan menggunakan thread utama instead of menggunakan thread lain, dan dia nggak ngerasain paralelisme dari multi-threading.
Memang teknik-tekniknya lumayan ribet sih untuk konsep yang seperti ini, InsyaAllah nanti gw juga bahas soal ini. 🙂
Yang pasti kalau kita dealing sama multithread perlu consider mengenai hubungan dengan control, khusus-nya UI Control WindowsForm tidak semua control dapat digunakan sebagai multithread sehingga kalau synchronize antara thread dengan thread lainnya untuk locking between thread gak banyak manfaatnya, dan crash will happen it you play dirty. Sehingga debungging takes more times rather than development.
Untuk di WPF situasi agak berbeda karena hal tsb sudah dipersiapkan matang oleh MS, belajar dari windows platform….sesuai dengan architecture nya…
sebagai referensi untuk Windows Client bermain di multithread mungkin ini bisa berguna…
Just Keep continue this article…
Windows Form
http://msdn.microsoft.com/en-us/magazine/cc164037.aspx
WPF
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
Regards