Pelajaran apa yang Anda pelajari dari proyek yang hampir / benar-benar gagal karena multithreading yang buruk?
Kadang-kadang, kerangka kerja memaksakan model threading tertentu yang membuat urutan urutan besarnya lebih sulit untuk diperbaiki.
Bagi saya, saya belum pulih dari kegagalan terakhir dan saya merasa lebih baik saya tidak mengerjakan apa pun yang berkaitan dengan multithreading dalam kerangka itu.
Saya menemukan bahwa saya bagus dalam masalah multithreading yang memiliki fork / join sederhana, dan di mana data hanya bergerak dalam satu arah (sementara sinyal dapat melakukan perjalanan dalam arah melingkar).
Saya tidak dapat menangani GUI di mana beberapa pekerjaan hanya dapat dilakukan pada utas yang disambungkan secara serial ("utas utama") dan pekerjaan lain hanya dapat dilakukan pada utas apa pun kecuali utas utama ("utas pekerja"), dan di mana data dan pesan harus melakukan perjalanan ke semua arah antara komponen N (grafik yang terhubung penuh).
Pada saat saya meninggalkan proyek itu untuk proyek lain, ada masalah kebuntuan di mana-mana. Saya mendengar bahwa 2-3 bulan kemudian, beberapa pengembang lain berhasil memperbaiki semua masalah kebuntuan, hingga dapat dikirim ke pelanggan. Saya tidak pernah berhasil menemukan bahwa saya tidak memiliki pengetahuan yang hilang.
Sesuatu tentang proyek: jumlah ID pesan (nilai integer yang menggambarkan arti dari suatu peristiwa yang dapat dikirim ke antrian pesan objek lain, terlepas dari threading) mencapai beberapa ribu. String unik (pesan pengguna) juga mengalami sekitar seribu.
Ditambahkan
Analogi terbaik yang saya dapatkan dari tim lain (tidak terkait dengan proyek saya dulu atau sekarang) adalah "memasukkan data ke dalam basis data". ("Basis data" mengacu pada sentralisasi dan pembaruan atom.) Dalam GUI yang terpecah menjadi beberapa tampilan, semua berjalan pada "utas utama" yang sama dan semua pengangkatan berat non-GUI dilakukan dalam utas pekerja individu, data aplikasi harus disimpan dalam satu tempat yang bertindak seperti Database, dan biarkan "Database" menangani semua "pembaruan atom" yang melibatkan dependensi data yang tidak sepele. Semua bagian lain dari GUI hanya menangani gambar layar dan tidak ada yang lain. Bagian UI dapat men-cache hal-hal dan pengguna tidak akan melihat jika basi hanya sepersekian detik, jika itu dirancang dengan benar. "Database" ini juga dikenal sebagai "dokumen" dalam arsitektur Document-View. Sayangnya - tidak, aplikasi saya sebenarnya menyimpan semua data di Views. Saya tidak tahu mengapa seperti itu.
Kontributor kontributor:
(kontributor tidak perlu menggunakan contoh nyata / pribadi. Pelajaran dari contoh anekdotal, jika dinilai sendiri dapat dipercaya, juga diterima.)
Jawaban:
Pelajaran favorit saya - sangat sulit dimenangkan! - adalah bahwa dalam program multithreaded, penjadwal adalah babi licik yang membenci Anda. Jika ada yang salah, mereka akan melakukannya, tetapi dengan cara yang tak terduga. Dapatkan sesuatu yang salah, dan Anda akan mengejar heisenbugs aneh (karena setiap instrument yang Anda tambahkan akan mengubah timing dan memberi Anda pola lari yang berbeda).
Satu-satunya cara yang waras untuk memperbaikinya adalah dengan benar - benar mengunci semua penanganan thread menjadi sekecil kode yang membuatnya baik-baik saja dan yang sangat konservatif tentang memastikan bahwa kunci dipegang dengan benar (dan dengan urutan akuisisi yang konstan secara global juga) . Cara termudah untuk melakukannya adalah tidak membagikan memori (atau sumber daya lainnya) di antara utas kecuali untuk olahpesan yang harus tidak sinkron; yang memungkinkan Anda menulis segala sesuatu dengan gaya yang tidak dikenali oleh utas. (Bonus: menskalakan ke beberapa mesin dalam sebuah cluster jauh lebih mudah.)
sumber
is that in a multithreaded program the scheduler is a sneaky swine that hates you.
- tidak, itu tidak tepat seperti yang Anda suruh :)Berikut adalah beberapa pelajaran dasar yang dapat saya pikirkan saat ini (bukan dari proyek gagal tetapi dari masalah nyata yang terlihat pada proyek nyata):
sumber
Kami mewarisi bagian di mana proyek GUI menggunakan selusin utas. Ini memberi apa-apa selain masalah. Jalan buntu, masalah balap, panggilan GUI lintas benang ...
sumber
Java 5 dan yang lebih baru memiliki Pelaksana yang dimaksudkan untuk membuat hidup lebih mudah untuk menangani program multi-threading fork-join style.
Gunakan itu, itu akan menghilangkan banyak rasa sakit.
(dan, ya, ini saya pelajari dari sebuah proyek :))
sumber
Saya memiliki latar belakang dalam sistem embedded realtime yang sulit. Anda tidak dapat menguji tidak adanya masalah yang disebabkan oleh multithreading. (Terkadang Anda dapat mengkonfirmasi keberadaan). Kode harus terbukti benar. Jadi praktik terbaik di sekitar setiap dan semua interaksi utas.
sumber
Analogi dari kelas multithreading yang saya ambil tahun lalu sangat membantu. Sinkronisasi ulir seperti sinyal lalu lintas yang melindungi persimpangan (data) agar tidak digunakan oleh dua mobil (utas) sekaligus. Kesalahan yang dilakukan banyak pengembang adalah menyalakan lampu merah di sebagian besar kota untuk membiarkan satu mobil lewat karena mereka pikir terlalu sulit atau berbahaya untuk mengetahui sinyal persis yang mereka butuhkan. Itu mungkin bekerja dengan baik ketika lalu lintas sepi, tetapi akan menyebabkan kemacetan saat aplikasi Anda tumbuh.
Itu adalah sesuatu yang sudah saya ketahui dalam teori, tetapi setelah kelas itu analogi itu benar-benar melekat pada saya, dan saya kagum seberapa sering setelah itu saya akan menyelidiki masalah threading dan menemukan satu antrian raksasa, atau menyela dimatikan di mana-mana selama menulis ke variabel hanya dua utas yang digunakan, atau muteks ditahan lama ketika itu bisa di refactored untuk menghindarinya sama sekali.
Dengan kata lain, beberapa masalah threading terburuk disebabkan oleh usaha keras yang berusaha menghindari masalah threading.
sumber
Coba lakukan lagi.
Setidaknya bagi saya, apa yang menciptakan perbedaan adalah latihan. Setelah melakukan pekerjaan multi-threaded dan didistribusikan beberapa kali Anda hanya bisa menguasainya.
Saya pikir debugging benar-benar yang membuatnya sulit. Saya dapat men-debug kode multi-threaded menggunakan VS tapi saya benar-benar bingung jika saya harus menggunakan gdb. Kesalahan saya, mungkin.
Hal lain yang dipelajari lebih lanjut adalah mengunci struktur data gratis.
Saya pikir pertanyaan ini dapat benar-benar ditingkatkan jika Anda menentukan kerangka kerjanya. .NET thread pools dan pekerja latar belakang benar-benar berbeda dari QThread, misalnya. Selalu ada beberapa platform khusus Gotcha.
sumber
Saya telah belajar bahwa panggilan balik dari modul tingkat lebih rendah ke modul tingkat lebih tinggi adalah kejahatan besar karena mereka menyebabkan memperoleh kunci dalam urutan yang berlawanan.
sumber