Konkurensi komposable di Jawa atau bahasa pemrograman lainnya

8

Sementara saya membaca sebuah makalah penelitian tentang konkurensi bernama Perangkat Lunak dan Revolusi Konkurensi ( versi html ). Saya menemukan garis berikut:

Sayangnya, meskipun kunci berfungsi, mereka menimbulkan masalah serius bagi pengembangan perangkat lunak modern. Masalah mendasar dengan kunci adalah bahwa kunci tidak dapat dikomposisikan . Anda tidak dapat mengambil dua potong kode berbasis kunci yang benar, menggabungkannya, dan tahu bahwa hasilnya masih benar. Pengembangan perangkat lunak modern bergantung pada kemampuan untuk menyusun pustaka ke dalam program yang lebih besar, dan karenanya merupakan kesulitan serius bahwa kita tidak dapat membangun komponen berbasis kunci tanpa memeriksa implementasinya.

  1. Saya sedang berpikir, bagaimana Java menjamin concurrency yang dapat dikompilasi atau bahkan ada cara untuk menghasilkan skenario ini.

  2. Dan bagaimana kita bisa menyinkronkan data di satu atau lebih perpustakaan? Dapatkah seorang programmer melakukannya dari programnya atau terserah perpustakaan untuk menyinkronkan sesuatu.

  3. Jika tidak Java maka apakah ada bahasa lain yang menggunakan konkurensi berbasis kunci dan menjamin konkurensi gabungan?

Berikut ini juga diambil dari kertas yang sama:

Setidaknya ada tiga masalah utama dengan metode yang disinkronkan. Pertama, mereka tidak sesuai untuk tipe yang metodenya memanggil fungsi virtual pada objek lain (misalnya, Java's Vector dan .NET's SyncHashTable), karena memanggil kode pihak ketiga sambil memegang kunci membuka kemungkinan kebuntuan . Kedua, metode yang disinkronkan dapat melakukan terlalu banyak penguncian, dengan memperoleh dan melepaskan kunci pada semua instance objek, bahkan yang tidak pernah dibagikan di seluruh utas (biasanya mayoritas). Ketiga, metode yang disinkronkan juga dapat melakukan penguncian terlalu sedikit, dengan tidak menjaga keaslian ketika suatu program memanggil beberapa metode pada suatu objek atau pada objek yang berbeda. Sebagai contoh sederhana dari yang terakhir, pertimbangkan transfer perbankan: account1.Credit (jumlah); account2.Debit (jumlah) ...

Catatan: Kertas diterbitkan pada September 2005

agas
sumber
Kertas @ErikEidt memiliki 94 Kutipan
3
Bukan jawaban untuk pertanyaan itu, tetapi Anda mendapatkan konkurensi yang jauh lebih baik ketika Anda membatasi interaksi pada pengiriman pesan: Proses (proses penuh, bukan hanya utas) berkomunikasi melalui antrian pesan yang tidak sinkron. Benar, ini tidak sebagus model berbasis ancaman, tetapi jika pengiriman pesan tidak dapat diblokir, Anda tidak bisa menemui jalan buntu kecuali jika Anda memiliki ketergantungan data sirkuler yang nyata pada pesan Anda. Yang paling penting, pesan apa pun secara sepele disusun / ditafsirkan sebagai operasi atom, sehingga semua sakit kepala dari kondisi yang konsisten hilang.
cmaster - mengembalikan monica
1
Perangkat Lunak Memori Transaksional adalah konstruk konkurensi yang dapat dikomposisikan. Haskell memiliki perpustakaan STM.
badai
1
@enguin: concurrency! = paralelisme. Javascript (node.js) adalah contoh yang baik dari bahasa dengan konkurensi yang sangat tinggi (memang semua I / O bersamaan) tetapi berurutan tunggal. Java memiliki kerangka kerja yang cukup baik untuk ini dalam bentuk Futures (CompletionStage). Tentu saja, seberapa bebas kode Anda tergantung pada implementasi tetapi alat-alat tersedia untuk Anda kembangkan.
slebetman

Jawaban:

7

Itu bukan bahasa Jawa. Itu sifat kunci (mutex).

Ada beberapa cara yang lebih baik untuk mendapatkan konkurensi yang ditingkatkan sambil tetap menjamin kebenaran, cara-cara yang independen bahasa:

  1. Menggunakan benda yang tidak dapat diubah, sehingga Anda tidak perlu kunci.
  2. Menggunakan gaya janji dan kelanjutan-lewat.
  3. Menggunakan struktur data bebas kunci.
  4. Menggunakan Memori Transaksional Perangkat Lunak untuk berbagi keadaan dengan aman.

Semua teknik ini memungkinkan peningkatan konkurensi tanpa menggunakan kunci. Tak satu pun dari mereka bergantung pada bahasa Jawa secara khusus.

Robert Harvey
sumber
3

Saya sedang berpikir, bagaimana Java menjamin concurrency yang dapat dikompilasi atau bahkan ada cara untuk menghasilkan skenario ini.

Seperti yang dikatakan artikel itu, tidak mungkin untuk menjamin kompabilitas ketika menggunakan kunci bersama dengan metode virtual (atau mekanisme serupa lainnya, seperti fungsi lewat sebagai parameter). Jika sepotong kode memiliki akses ke metode virtual yang berasal dari potongan kode lain dan keduanya berpotensi menggunakan kunci, maka untuk aman (yaitu tanpa risiko kebuntuan) menyusun dua potong kode, Anda perlu memeriksa kode sumber dari kedua.

Dan bagaimana kita bisa menyinkronkan data di satu atau lebih perpustakaan? Dapatkah seorang programmer melakukannya dari programnya atau terserah perpustakaan untuk menyinkronkan sesuatu.

Secara umum, tergantung pada pemrogram yang menggunakan perpustakaan untuk melakukan sinkronisasi. Dengan begitu, programmer mengetahui di mana semua kunci berada dan mereka dapat memastikan mereka tidak menemui jalan buntu.

Jika tidak Java maka apakah ada bahasa lain yang menggunakan konkurensi berbasis kunci dan menjamin konkurensi gabungan?

Sekali lagi, intinya dari artikel ini adalah bahwa ini tidak mungkin.

svick
sumber
Makalah ini diterbitkan pada tahun 2005. Jawaban Anda didasarkan pada kertas yang sama. Bahasa telah berkembang pesat sejak tahun 2005. Bisakah Anda memberikan referensi terbaru atau Anda dapat mengonfirmasi ulang jawaban Anda.
2
Makalah itu tidak berbicara tentang apa pun yang khusus untuk tahun 2005. Masih benar pada tahun 2105 bahwa pustaka berbasis kunci tidak dapat dikomposisikan.
svick
Java terus memperbarui konstruksinya yang mengunci, Anda dapat membandingkan paket konkurensi Java di Java5 hingga Java8.
Tidak masalah. Java 8 tentu tidak menghilangkan kemungkinan kebuntuan saat menggunakan kunci, jadi tidak ada yang berubah tentang ini.
svick
2
@enguin - Tidak mungkin membuat bahasa yang sepenuhnya dapat dikomposisikan setelah memiliki fitur yang tidak dapat dikomposasikan, karena Anda tidak dapat menjamin bahwa modul tertutup tidak menggunakannya dengan cara yang berbahaya. Anda dapat membuat kode Anda dapat dikompilasi, bahkan jika Anda menggunakan kunci (meskipun Anda harus berhati-hati tentang cara menggunakannya dalam kasus ini), tetapi Anda tidak dapat memastikan bahwa perpustakaan arbitrer dan / atau komponen sistem tidak.
Jules
1

Mekanisme penguncian tingkat rendah pada dasarnya tidak dapat dikomposisikan. Ini sebagian besar karena kunci mencapai di bawah dunia untuk memengaruhi mesin yang menjalankan instruksi.

Perpustakaan Java berikutnya telah menambahkan mekanisme tingkat yang lebih tinggi dan lebih tinggi untuk memastikan operasi multithreaded yang benar. Mereka melakukan ini dengan membatasi penggunaan lock()dan volatileuntuk keadaan yang diketahui dan terkendali tertentu. Sebagai contoh, implementasi antrian konkuren memiliki perilaku yang sangat terlokalisasi dan memungkinkan alasan tentang sebelum dan sesudah negara. Menggunakan mekanisme tingkat yang lebih tinggi berarti Anda perlu membaca lebih sedikit dari spesifikasi atau kode untuk memperbaikinya. Tapi, dan ini adalah besar tetapi, Anda masih perlu memahami model penguncian dari setiap subsistem dan bagaimana mereka berinteraksi satu sama lain. Juga, perubahan dalam Java untuk konkurensi setelah Java 5 hampir secara eksklusif terkait dengan perpustakaan dan bukan bahasa.

Masalah utama dengan mekanisme penguncian apa pun adalah bahwa hal itu memengaruhi status dan beroperasi dalam domain waktu. Baik manusia maupun komputer tidak memiliki alasan yang baik tentang keadaan atau waktu. Ini adalah kemampuan untuk berpikir tentang nilai dan struktur yang memungkinkan ilmuwan komputer untuk membuat monad, hal pertama yang muncul di benak saya sehubungan dengan kompabilitas dalam suatu bahasa.

Yang paling dekat dengan kami adalah Mengkomunikasikan Proses Berurutan . Ini masih membutuhkan mekanisme tingkat tinggi, seperti kotak surat dan pengiriman pesan. Menurut pendapat saya yang sederhana, CSP masih tidak berurusan dengan sistem besar (target akhir dari perangkat lunak komposer) atau alasan berbasis waktu.

BobDalgleish
sumber
1
Dosen ini tidak menjawab pertanyaan saya. Saya ingin tahu apakah Java komposer atau ada bahasa lain yang mana? Sesuai dengan dua jawaban yang saya dapatkan, Java tidak dapat dikompilasi tetapi kedua jawaban tidak memberikan bukti konkret.
Apakah Anda ingin bukti bahwa Java hanya menggunakan kunci tidak dapat dikomposit? Juga, jika Anda membaca artikel CSP di atas, Anda akan melihat banyak bahasa yang disebutkan yang komposable. Komentar saya merujuk pada bahasa apa pun di mana lock()dan volatilemerupakan perincian utas atau sinkronisasi proses.
BobDalgleish
Oke, ada sesuatu yang saya minati. Dalam jawaban Anda, Anda berkata, "Yang terdekat dengan kami ..." apa yang Anda maksud dengan itu. Bagaimana Anda mengetahui bahwa CSP adalah yang terdekat?
1

Pertama-tama saya berterima kasih kepada semua anggota yang menjawab pertanyaan ini, terutama Robert Harvey yang jawabannya sangat dekat dengan saya.

Saya telah meneliti konsep konkurensi selama dua tahun dan menurut temuan saya, tidak ada bahasa yang memberikan jaminan bahwa konstruk konkurensinya komposable. Kode berjalan yang sangat baik menggunakan struktur data yang tidak dapat diubah dan STM juga dapat menghasilkan hasil yang tidak terduga karena di bawah kap, STM menggunakan kunci. STM sangat baik untuk operasi atom, tetapi jika kita berbicara tentang kompabilitas kontras konkurensi antara modul, ada kemungkinan (sangat sedikit) bahwa STM mungkin tidak berfungsi seperti yang diharapkan.

Tapi tetap saja, kita bisa meminimalkan ketidakpastian dengan menggunakan yang berikut (teknik / metode / konstruksi):

  1. Menghindari kunci dan sinkronisasi
  2. Menggunakan STM
  3. Menggunakan struktur data yang persisten (tidak berubah)
  4. Menghindari berbagi negara
  5. Fungsi murni
  6. Gaya pemrograman tidak sinkron
  7. Menghindari pergantian konteks yang sering
  8. Paradigma multi-threading dan sifat lingkungannya memainkan peran utama

Mungkin keberatan paling mendasar [...] adalah bahwa program berbasis kunci tidak menulis: fragmen yang benar mungkin gagal saat digabungkan. —Tim Harris et al., "Transaksi Memori yang Dapat Dikomposisikan", Bagian 2: Latar Belakang, hal.2

Memperbarui

Berkat Jules, saya berdiri terkoreksi. STM menggunakan berbagai implementasi dan kebanyakan dari mereka bebas dari penguncian. Tapi saya masih percaya bahwa STM adalah solusi yang baik di sini, tetapi bukan yang sempurna, dan memiliki kekurangan:

Setiap membaca (atau menulis) dari lokasi memori dari dalam transaksi dilakukan dengan panggilan ke rutinitas STM untuk membaca (atau menulis) data. Dengan kode sekuensial, akses ini dilakukan oleh instruksi CPU tunggal. STM membaca dan menulis rutin secara signifikan lebih mahal daripada instruksi CPU yang sesuai karena mereka, biasanya, harus memelihara data pembukuan tentang setiap akses. Sebagian besar STM memeriksa konflik dengan transaksi konkuren lainnya, mencatat akses, dan dalam hal penulisan, catat nilai saat ini (atau yang lama) dari data, selain membaca atau menulis lokasi memori yang diakses. Beberapa operasi ini menggunakan instruksi sinkronisasi mahal dan mengakses metadata bersama, yang selanjutnya meningkatkan biaya mereka. Semua ini mengurangi kinerja single-threaded bila dibandingkan dengan kode sekuensial. - Mengapa STM bisa lebih dari sekadar mainan penelitian - halaman 1

Lihat juga makalah ini:

Koran-koran ini berumur beberapa tahun. Banyak hal mungkin telah berubah / membaik tetapi tidak semua.

CanProgram
sumber
"Kode berjalan yang sangat baik menggunakan struktur data yang tidak dapat diubah dan STM juga dapat menghasilkan hasil yang tidak terduga karena di bawah kap STM menggunakan kunci." Bisakah Anda memberikan contoh hasil yang tidak terduga? Sejauh yang saya ketahui, STM dianggap dapat diandalkan dan komposer, tetapi mungkin Anda menyadari sesuatu yang tidak saya ...?
Jules
Juga, Anda menyatakan bahwa STM "menggunakan kunci", tapi itu hanya detail implementasi beberapa versi saja. STM dapat diimplementasikan dalam sistem yang sepenuhnya bebas kunci dengan menggunakan pembaruan atom; lihat dl.acm.org/citation.cfm?id=1941579
Jules
1

Saya telah mendengarnya mengatakan oleh para peneliti yang dihormati bahwa mekanisme sinkronisasi yang berguna dapat digunakan untuk membangun jalan buntu. Memori Transaksional (apakah perangkat keras atau perangkat lunak) tidak berbeda. Misalnya, pertimbangkan pendekatan ini untuk menulis penghalang utas:

transaction {
    counter++;
}

while (true) {
    transaction {
        if (counter == num_threads)
            break;
    }
}

(Catatan: contoh diambil dari kertas oleh Yannis Smaragdakis di PACT 2009)

Jika kita mengabaikan fakta bahwa ini bukan cara yang baik untuk menyinkronkan sejumlah besar utas, tampaknya itu benar. Tapi itu tidak komposable. Keputusan untuk memasukkan logika ke dalam dua transaksi sangat penting. Jika kita menyebutnya dari transaksi lain, sehingga semuanya diratakan menjadi satu transaksi, maka kita mungkin tidak akan pernah menyelesaikannya.

Hal yang sama berlaku untuk saluran yang lewat pesan: siklus komunikasi dapat menyebabkan kebuntuan. Sinkronisasi ad-hoc dengan atom C ++ dapat menyebabkan kebuntuan. RCU, kunci urutan, kunci pembaca / penulis, variabel kondisi, dan semafor dapat digunakan untuk membuat deadlock.

Itu tidak berarti bahwa transaksi atau saluran (atau kunci atau RCU) buruk. Sebaliknya, itu untuk mengatakan bahwa beberapa hal sepertinya tidak mungkin. Mekanisme kontrol konkurensi yang dapat diukur, dapat disusun, bebas patologi mungkin tidak memungkinkan.

Cara terbaik untuk menghindari masalah adalah tidak mencari mekanisme peluru perak, tetapi untuk menggunakan pola yang baik dengan seksama. Dalam dunia komputasi paralel, titik awal yang baik adalah Pemrograman Paralel Terstruktur: Pola Komputasi Efisien , oleh Arch Robison, James Reinders, dan Michael McCool. Untuk pemrograman bersamaan, ada beberapa pola yang bagus (lihat komentar @ gardenhead), tetapi programmer C ++ dan Java tidak akan menggunakannya. Satu pola yang lebih banyak orang dapat mulai menggunakan cara-cara yang benar adalah mengganti sinkronisasi ad-hoc dalam program-program dengan antrian multi-konsumen multi-produsen. Dan TM jelas lebih baik daripada kunci, karena meningkatkan tingkat abstraksi, sehingga pemrogram fokus pada apa yang perlu menjadi atom , bukanbagaimana menerapkan protokol kunci pintar untuk memastikan atomicity . Mudah-mudahan, ketika perangkat keras TM meningkat dan bahasa menambahkan lebih banyak dukungan TM, kita akan mencapai titik di mana TM mengganti kunci dalam kasus umum.

Mike Spear
sumber
1
"Untuk pemrograman bersamaan, polanya tidak berkembang dengan baik." Ini benar-benar salah. Model komputasi bersamaan kembali ke dekade sebelumnya. Model aktor ditemukan pada awal 70-an, dan berbagai bentuk kalkulus proses telah ditemukan dan dipelajari sejak saat itu juga. Masalahnya bukan terletak pada model perhitungan yang baik; itu terletak pada programmer yang tidak mau menggunakan model-model itu dan kemungkinan inefisiensi dalam implementasinya.
Gardenhead
Poin luar biasa, @ kepala kepala. Model telah dikembangkan, hanya saja tidak ada yang menggunakannya. Saya akan mengedit respons saya.
Mike Spear