Bagaimana menjelaskan mengapa multi-threading sulit


84

Saya seorang programmer yang cukup baik, bos saya juga seorang programmer yang cukup baik. Meskipun ia tampaknya meremehkan beberapa tugas seperti multi-threading dan betapa sulitnya hal itu (saya merasa sangat sulit untuk hal lain selain menjalankan beberapa utas, menunggu semuanya selesai, lalu mengembalikan hasil).

Saat Anda mulai harus khawatir tentang kebuntuan dan kondisi balapan, saya merasa sangat sulit, tetapi bos tampaknya tidak menghargai ini - saya tidak berpikir dia pernah menemukan ini. Hanya menampar kunci di atasnya cukup banyak sikap.

Jadi bagaimana saya bisa memperkenalkannya, atau menjelaskan mengapa ia mungkin meremehkan kompleksitas konkurensi, paralelisme, dan multi-threading? Atau mungkin saya salah?

Sunting: Hanya sedikit tentang apa yang telah dia lakukan - loop melalui daftar, untuk setiap item dalam daftar itu buat utas yang mengeksekusi perintah pembaruan basis data berdasarkan informasi dalam item itu. Saya tidak yakin bagaimana dia mengendalikan berapa banyak thread yang dieksekusi sekaligus, saya kira dia pasti telah menambahkannya ke antrian jika ada terlalu banyak yang berjalan (dia tidak akan menggunakan semaphore).


17
Multi-threading mudah. Sinkronisasi yang benar sulit dilakukan.
Vineet Reynolds

33
Bawa tiga orang ke dalam ruangan, lebih disukai dengan aksen yang berbeda, dan minta mereka menjelaskan bagian yang berbeda, yang tumpang tindih dari masalah konkurensi .... bersamaan.
greyfade

Multithreading bisa sangat sulit atau sangat mudah, tergantung pada masalah yang dihadapi dan pada dukungan bahasa. Clojure memudahkan clojure.org/concurrent_programming
Job

4
@Job Pemrograman serentak selalu sulit (dalam proyek dunia nyata), apa pun bahasa yang Anda gunakan. Scala, Clojure, atau Erlang membuatnya sedikit waras ketika Anda ingin membandingkannya dengan bahasa yang menggunakan dan mendorong status yang bisa berubah.
Chiron

4
Metafora favorit saya untuk ini adalah: "Apakah Anda akan minum pil tidur dan obat pencahar sekaligus?" Bahkan menggunakan antrian pesan yang kompleks, ketertiban adalah buah dari konkurensi yang dilakukan dengan benar . Itu, kecuali Anda memiliki besar kesepakatan pengalaman dengan itu, adalah sulit bagi banyak orang.
Tim Post

Jawaban:


29
  1. Jika Anda dapat mengandalkan pengalaman matematika apa pun, ilustrasikan bagaimana aliran eksekusi normal yang pada dasarnya deterministik menjadi tidak hanya tidak deterministik dengan beberapa utas, tetapi kompleks secara eksponensial , karena Anda harus memastikan setiap interleaving instruksi mesin yang mungkin masih akan melakukan hal yang benar. Contoh sederhana dari pembaruan yang hilang atau situasi membaca kotor sering kali membuka mata.

  2. "Menampar kunci" adalah solusi sepele ... itu menyelesaikan semua masalah Anda jika Anda tidak peduli dengan kinerja. Cobalah untuk mengilustrasikan seberapa besar kinerja yang akan terjadi jika, misalnya, Amazon harus mengunci seluruh pantai timur setiap kali seseorang di Atlanta memesan satu buku!


1
1 untuk diskusi tentang kompleksitas matematika - ini adalah bagaimana saya memahami kesulitan dalam konkurensi berbagi-negara, dan merupakan argumen yang umumnya saya buat dalam mengadvokasi arsitektur pesan-lewat. -1 untuk "menampar kunci di atasnya" ... Ungkapan ini mengartikan pendekatan yang tidak terpikirkan untuk penggunaan kunci, yang kemungkinan besar akan menyebabkan kebuntuan, atau perilaku yang tidak konsisten (karena klien kode Anda yang hidup di utas berbeda membuat pertentangan. permintaan, tetapi jangan menyinkronkan di antara mereka sendiri, klien akan memiliki model yang tidak sesuai dari negara perpustakaan Anda).
Aidan Cully

2
Amazon memang harus mengunci inventaris barang individual di satu gudang sebentar saat memproses pesanan. Jika ada operasi besar yang tiba-tiba pada satu item tertentu, kinerja pemesanan untuk item tersebut akan berkurang hingga persediaan habis dan akses ke inventaris menjadi hanya-baca (dan karenanya 100% dapat dibagikan). Satu hal yang dilakukan Amazon untuk hal itu yang tidak dilakukan oleh program lain adalah kemampuan untuk mengantri pesanan sampai stok kembali terjadi dan opsi untuk melayani pesanan yang antri sebelum stok ulang tersedia untuk pesanan baru.
Blrfl

@ Blrfl: Program dapat melakukannya jika ditulis menggunakan pesan yang lewat melalui antrian. Tidak perlu memiliki semua pesan ke utas tertentu melalui antrian tunggal ...
Donal Fellows

4
@Donal Fellows: Jika ada stok 1 juta stok di satu gudang dan 1 juta pesanan tiba pada saat yang bersamaan, semua permintaan tersebut diserialisasi pada tingkat tertentu sambil mencocokkan item dengan pesanan, tidak peduli bagaimana mereka ditangani. Kenyataan praktisnya adalah bahwa Amazon mungkin tidak pernah memiliki begitu banyak widget yang tersedia sehingga latensi dalam memproses pesanan menjadi sangat tinggi sebelum inventaris habis dan semua orang dalam antrean dapat diberitahu (secara paralel), "kami kehabisan. " Antrian pesan adalah cara yang bagus untuk mencegah kebuntuan, tetapi mereka tidak menyelesaikan masalah pertengkaran tinggi untuk sumber daya terbatas.
Blrfl

79

Multi-threading adalah sederhana. Pengodean aplikasi untuk multi-threading sangat, sangat mudah.

Ada trik sederhana, dan ini adalah dengan menggunakan antrian pesan yang dirancang dengan baik (jangan tidak roll sendiri) untuk melewati data antara benang.

Bagian yang sulit adalah mencoba membuat beberapa utas secara ajaib memperbarui objek yang dibagikan dengan beberapa cara. Saat itulah ia rawan kesalahan karena orang-orang tidak memperhatikan kondisi balapan yang ada.

Banyak orang tidak menggunakan antrian pesan dan mencoba memperbarui objek yang dibagikan dan membuat masalah sendiri.

Yang menjadi sulit adalah merancang algoritma yang berfungsi dengan baik ketika mengirimkan data di antara beberapa antrian. Itu sulit. Tetapi mekanisme utas yang ada bersama (melalui antrian bersama) mudah.

Juga, perhatikan bahwa utas berbagi sumber daya I / O. Program terikat I / O (mis., Koneksi jaringan, operasi file atau operasi basis data) tidak mungkin berjalan lebih cepat dengan banyak utas.

Jika Anda ingin mengilustrasikan masalah pembaruan objek yang dibagikan, itu mudah. Duduk di seberang meja dengan seikat kartu kertas. Tuliskan satu set perhitungan sederhana - 4 atau 6 formula sederhana - dengan banyak ruang di halaman.

Ini permainannya. Anda masing-masing membaca rumus, menulis jawaban dan meletakkan kartu dengan jawabannya.

Anda masing-masing akan melakukan setengah pekerjaan, bukan? Anda sudah selesai separuh waktu, bukan?

Jika bos Anda tidak banyak berpikir dan baru mulai, Anda akan berakhir dengan pertentangan dalam beberapa cara dan keduanya menulis jawaban untuk rumus yang sama. Itu tidak berhasil karena ada kondisi ras yang melekat di antara Anda berdua membaca sebelum menulis. Tidak ada yang menghentikan Anda dari keduanya membaca formula yang sama dan menimpa jawaban masing-masing.

Ada banyak, banyak cara untuk menciptakan kondisi balapan dengan sumber daya yang buruk atau tidak terkunci.

Jika Anda ingin menghindari semua konflik, Anda memotong kertas menjadi tumpukan formula. Anda mengambil satu dari antrian, menuliskan jawabannya, dan memposting jawabannya. Tidak ada konflik karena Anda berdua membaca dari antrian pesan hanya satu pembaca.


Bahkan memotong kertas menjadi tumpukan tidak sepenuhnya memperbaiki keadaan - Anda masih memiliki situasi di mana Anda dan bos Anda meraih formula baru pada saat yang sama dan Anda memukul buku-buku jari Anda ke dalamnya. Bahkan, saya akan mengatakan bahwa ini adalah jenis masalah threading yang paling umum. Kesalahan yang sangat kotor ditemukan lebih awal. Kesalahan yang benar-benar tidak biasa bertahan selamanya karena tidak ada yang bisa mereproduksi mereka, Kondisi ras yang masuk akal - seperti ini - terus muncul dalam pengujian, dan akhirnya semua (atau lebih mungkin sebagian besar) dari mereka akan disetrika.
Airsource Ltd

@AirsourceLtd Apa sebenarnya yang Anda katakan dengan "memukul buku-buku jari Anda menjadi miliknya"? Selama Anda memiliki antrian pesan yang mencegah dua utas berbeda dari mengambil pesan yang sama, itu tidak akan menjadi masalah. Kecuali saya salah paham apa yang Anda maksudkan.
Zack

25

Pemrograman multi-threaded mungkin merupakan solusi paling sulit untuk konkurensi. Ini pada dasarnya adalah abstraksi level rendah dari apa yang sebenarnya dilakukan mesin.

Ada sejumlah pendekatan, seperti model aktor atau memori transaksional (perangkat lunak) , yang jauh lebih mudah. Atau bekerja dengan struktur data yang tidak dapat diubah (seperti daftar dan pohon).

Secara umum, pemisahan keprihatinan yang tepat membuat multi-threading lebih mudah. Sesuatu, yang sering terlupakan, ketika orang menelurkan 20 utas, semua berusaha memproses buffer yang sama. Gunakan reaktor di mana Anda memerlukan sinkronisasi dan umumnya mengirimkan data antara pekerja yang berbeda dengan antrian pesan.
Jika Anda memiliki kunci dalam logika aplikasi Anda, Anda melakukan sesuatu yang salah.

Jadi ya, secara teknis, multi-threading sulit.
"Menampar kunci di atasnya" adalah solusi yang paling tidak dapat diskalakan untuk masalah konkurensi, dan sebenarnya mengalahkan seluruh tujuan multi-threading. Apa yang dilakukannya adalah mengembalikan masalah kembali ke model eksekusi non-konkuren. Semakin banyak Anda melakukannya, semakin besar kemungkinannya, bahwa Anda hanya memiliki satu utas berjalan pada saat itu (atau 0 dalam kebuntuan). Itu mengalahkan seluruh tujuan.
Ini seperti mengatakan "Memecahkan masalah dunia ke-3 itu mudah. ​​Hanya melempar bom ke atasnya." Hanya karena ada solusi sepele, ini tidak membuat masalah sepele, karena Anda peduli dengan kualitas hasilnya.

Namun dalam praktiknya, menyelesaikan masalah ini sama sulitnya dengan masalah pemrograman lainnya dan paling baik dilakukan dengan abstraksi yang sesuai. Yang membuatnya sebenarnya cukup mudah.


14

Saya pikir ada sudut pandang non teknis untuk pertanyaan ini - IMO ini masalah kepercayaan. Kami biasanya diminta untuk mereproduksi aplikasi yang kompleks seperti - oh, saya tidak tahu - Facebook misalnya. Saya sampai pada kesimpulan bahwa jika Anda harus menjelaskan kompleksitas tugas kepada yang belum tahu / manajemen - maka ada sesuatu yang busuk di Denmark.

Bahkan jika programmer ninja lain dapat melakukan tugas dalam 5 menit, perkiraan Anda didasarkan pada kemampuan pribadi Anda. Teman bicara Anda harus belajar untuk mempercayai pendapat Anda tentang masalah ini atau mempekerjakan seseorang yang kata-katanya ingin mereka terima.

Tantangannya bukan dalam menyampaikan implikasi teknis, yang orang cenderung abaikan atau tidak dapat pahami melalui percakapan, tetapi dalam membangun hubungan yang saling menghormati.


1
Jawaban yang menarik, meskipun itu adalah pertanyaan teknis. Namun saya setuju dengan apa yang Anda katakan ... dalam hal ini, manajer saya adalah seorang programmer yang cukup bagus, namun saya hanya berpikir karena ia belum menemukan kerumitan aplikasi multi-utas, ia meremehkannya.
Tuan Shoubs

6

Salah satu eksperimen pemikiran sederhana untuk memahami kebuntuan adalah masalah " filsuf makan ". Salah satu contoh yang cenderung saya gunakan untuk menggambarkan bagaimana kondisi balapan yang buruk adalah situasi Therac 25 .

"Hanya menampar kunci" adalah mentalitas seseorang yang belum menemukan bug yang sulit dengan multi-threading. Dan mungkin saja dia berpikir Anda melebih-lebihkan keseriusan situasi (saya tidak - mungkin untuk meledakkan barang atau membunuh orang dengan bug kondisi ras, terutama dengan perangkat lunak tertanam yang berakhir di mobil).


1
yaitu masalah sandwich: Anda membuat tumpukan sandwich, tetapi hanya ada 1 hidangan mentega dan 1 pisau. Pada umumnya semua baik-baik saja tetapi pada akhirnya seseorang akan mengambil mentega sementara orang lain mengambil pisau .. dan kemudian mereka berdua berdiri di sana menunggu yang lain untuk melepaskan sumber daya mereka.
gbjbaanb

Bisakah masalah kebuntuan seperti itu diselesaikan dengan selalu mendapatkan sumber daya dalam urutan yang ditetapkan?
compman

@ kompi, tidak. Karena dimungkinkan bagi 2 utas untuk mencoba meraih sumber daya yang sama pada saat yang sama, dan utas tersebut tidak selalu membutuhkan rangkaian sumber daya yang sama - hanya tumpang tindih yang cukup untuk menyebabkan masalah. Salah satu skema adalah menempatkan sumber daya "kembali" dan kemudian menunggu periode acak sebelum meraihnya lagi. Periode backoff ini terjadi di sejumlah protokol, yang paling awal adalah Aloha. en.wikipedia.org/wiki/ALOHAnet
Tangurena

1
Bagaimana jika setiap sumber daya dalam program memiliki nomor, dan ketika utas / proses membutuhkan seperangkat sumber daya, ia selalu mengunci sumber daya dalam meningkatkan urutan numerik? Saya tidak berpikir kebuntuan itu bisa terjadi.
compman

1
@ compman: Itu memang cara untuk menghindari kebuntuan. Dimungkinkan untuk merancang alat yang memungkinkan Anda memeriksa ini secara otomatis; jadi jika aplikasi Anda tidak pernah ditemukan untuk mengunci sumber daya selain dalam urutan numerik yang meningkat maka Anda tidak pernah mengalami kebuntuan potensial . (Perhatikan bahwa deadlock potensial hanya berubah menjadi deadlock nyata ketika kode Anda berjalan di komputer pelanggan).
gnasher729

3

Aplikasi bersamaan tidak deterministik. Dengan sejumlah kecil keseluruhan kode yang telah diakui oleh programmer sebagai rentan, Anda tidak dapat mengontrol kapan bagian dari utas / proses dijalankan dalam kaitannya dengan bagian mana pun dari utas lainnya. Pengujian lebih sulit, membutuhkan waktu lebih lama, dan tidak mungkin menemukan semua cacat terkait konkurensi. Cacat, jika ditemukan, seringkali halus tidak dapat direproduksi secara konsisten, maka memperbaiki itu sulit.

Oleh karena itu satu-satunya aplikasi konkuren yang benar adalah yang terbukti benar, sesuatu yang tidak sering dilakukan dalam pengembangan perangkat lunak. Akibatnya, jawaban oleh S.Lot adalah saran umum terbaik, karena pesan yang lewat relatif mudah dibuktikan benar.


3

Jawaban singkat dalam dua kata: NONDETERMINISME YANG DAPAT DITERIMA

Jawaban panjang: Itu tergantung pada pendekatan mana untuk pemrograman bersamaan yang Anda gunakan mengingat masalah Anda. Dalam buku Konsep, Teknik, dan Model Pemrograman Komputer , penulis dengan jelas menjelaskan empat pendekatan praktis utama untuk menulis program bersamaan:

  • Pemrograman berurutan : pendekatan dasar yang tidak memiliki konkurensi;
  • Konkurensi deklaratif : dapat digunakan ketika tidak ada nondeterminisme yang dapat diamati;
  • Konkurensi penyampaian pesan: penyampaian pesan bersamaan antara banyak entitas, tempat setiap entitas memproses pesan secara berurutan secara internal;
  • Konkurensi keadaan bersama : utas memperbarui objek pasif bersama melalui tindakan atom berbutir kasar, misalnya kunci, monitor, dan transaksi;

Sekarang yang paling mudah dari keempat pendekatan ini selain dari pemrograman sekuensial yang jelas adalah deklaratif konkurensi , karena program yang ditulis menggunakan pendekatan ini tidak memiliki nondeterminisme yang dapat diamati . Dengan kata lain, tidak ada kondisi ras , karena kondisi ras hanyalah perilaku nondeterministik yang dapat diamati.

Tetapi kurangnya nondeterminisme yang dapat diamati berarti, bahwa ada beberapa masalah yang tidak dapat kita atasi dengan menggunakan konkurensi deklaratif. Di sinilah dua pendekatan terakhir tidak begitu mudah ikut bermain. Bagian yang tidak mudah adalah konsekuensi dari nondeterminisme yang dapat diamati. Sekarang mereka berdua jatuh di bawah model konkuren stateful dan juga setara dalam ekspresif. Tetapi karena jumlah core yang terus meningkat per CPU, tampaknya industri baru-baru ini lebih tertarik pada konkurensi lewat pesan, seperti dapat dilihat pada naiknya pustaka lewat pesan (misalnya Akka untuk JVM) atau bahasa pemrograman (misalnya Erlang ) .

Pustaka Akka yang disebutkan sebelumnya, yang didukung oleh model Aktor teoritis menyederhanakan membangun aplikasi bersamaan, karena Anda tidak perlu lagi berurusan dengan kunci, monitor, atau transaksi. Di sisi lain itu membutuhkan pendekatan yang berbeda untuk merancang solusi, yaitu berpikir dengan cara bagaimana secara hierarkis menggabungkan aktor. Orang bisa mengatakan bahwa itu membutuhkan pola pikir yang sama sekali berbeda, yang lagi-lagi dapat menjadi lebih sulit daripada menggunakan konkurensi berbagi keadaan biasa.

Pemrograman bersamaan sulit dilakukan karena nondeterminisme yang dapat diamati, tetapi ketika menggunakan pendekatan yang tepat untuk masalah yang diberikan dan perpustakaan yang tepat yang mendukung pendekatan itu, maka banyak masalah dapat dihindari.


0

Saya pertama kali diajarkan bahwa hal itu dapat memunculkan masalah dengan melihat program sederhana yang memulai 2 utas dan membuat keduanya mencetak ke konsol pada waktu yang bersamaan dari 1-100. Dari pada:

1
1
2
2
3
3
...

Anda mendapatkan sesuatu yang lebih seperti ini:

1
2
1
3
2
3
...

Jalankan lagi dan Anda mungkin mendapatkan hasil yang sama sekali berbeda.

Sebagian besar dari kita telah dilatih untuk mengasumsikan bahwa kode kita akan dieksekusi secara berurutan. Dengan kebanyakan multi-threading kita tidak bisa menerima ini begitu saja "di luar kotak".


-3

Coba gunakan beberapa palu untuk tumbuk dalam sekelompok paku yang berjarak dekat sekaligus tanpa komunikasi antara mereka yang memegang palu ... (asumsikan bahwa mereka ditutup mata).

Tingkatkan ini untuk membangun rumah.

Sekarang cobalah tidur di malam hari membayangkan Anda adalah arsiteknya. :)


-3

Bagian yang mudah: gunakan multithreading dengan fitur kerangka kerja kontemporer, sistem operasi dan perangkat keras, seperti semaphore, antrian, penghitung yang saling bertautan, jenis kotak atom dll.

Bagian yang sulit: mengimplementasikan fitur-fitur itu sendiri tanpa menggunakan fitur di tempat pertama, mungkin kecuali beberapa kemampuan perangkat keras yang sangat terbatas, hanya mengandalkan jaminan pencatatan jam kerja yang koherensi di berbagai core.


3
Bagian yang sulit memang lebih sulit, tetapi bahkan bagian yang mudah pun tidak begitu mudah.
PeterAllenWebb
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.