Kisah konkurensi yang lebih baik adalah salah satu tujuan utama proyek Rust, jadi perbaikan harus diharapkan, asalkan kami memercayai proyek untuk mencapai tujuannya. Penafian penuh: Saya memiliki pendapat tinggi tentang Rust dan diinvestasikan di dalamnya. Seperti yang diminta, saya akan mencoba untuk menghindari penilaian nilai dan menjelaskan perbedaan daripada peningkatan (IMHO) .
Karat yang aman dan tidak aman
"Rust" terdiri dari dua bahasa: Satu yang berusaha sangat keras untuk mengisolasi Anda dari bahaya pemrograman sistem, dan yang lebih kuat tanpa aspirasi semacam itu.
Unsafe Rust adalah bahasa kasar, brutal yang terasa sangat mirip C ++. Hal ini memungkinkan Anda untuk melakukan hal-hal berbahaya yang sewenang-wenang, berbicara dengan perangkat keras, (mis-) mengelola memori secara manual, menembak diri sendiri, dll. Ini sangat mirip dengan C dan C ++ karena kebenaran program pada akhirnya ada di tangan Anda. dan tangan semua programmer lain yang terlibat di dalamnya. Anda memilih bahasa ini dengan kata kunci unsafe
, dan seperti dalam C dan C ++, satu kesalahan di satu lokasi dapat membuat seluruh proyek hancur.
Safe Rust adalah "default", sebagian besar kode Rust aman, dan jika Anda tidak pernah menyebutkan kata kunci unsafe
dalam kode Anda, Anda tidak pernah meninggalkan bahasa yang aman. Sisa posting sebagian besar akan menyangkut dirinya sendiri dengan bahasa itu, karena unsafe
kode dapat mematahkan setiap dan semua jaminan bahwa Rust bekerja sangat keras untuk memberi Anda. Di sisi lain, unsafe
kode tidak jahat dan tidak diperlakukan seperti itu oleh komunitas (namun, sangat tidak dianjurkan bila tidak diperlukan).
Ini berbahaya, ya, tetapi juga penting, karena memungkinkan membangun abstraksi yang menggunakan kode aman. Kode tidak aman yang baik menggunakan sistem tipe untuk mencegah orang lain menyalahgunakannya, dan oleh karena itu keberadaan kode tidak aman dalam program Rust tidak perlu mengganggu kode aman. Semua perbedaan berikut ada karena sistem tipe Rust memiliki alat yang tidak dimiliki C ++, dan karena kode tidak aman yang mengimplementasikan abstraksi konkurensi menggunakan alat ini secara efektif.
Non-perbedaan: Memori bersama / bisa berubah
Meskipun Rust lebih menekankan pada pengiriman pesan dan sangat ketat mengontrol memori bersama, itu tidak mengesampingkan concurrency memori bersama dan secara eksplisit mendukung abstraksi umum (kunci, operasi atom, variabel kondisi, koleksi bersamaan).
Selain itu, seperti C ++ dan tidak seperti bahasa fungsional, Rust sangat menyukai struktur data imperatif tradisional. Tidak ada daftar tertaut terus-menerus / tidak dapat diubah di perpustakaan standar. Ada std::collections::LinkedList
tapi seperti std::list
di C ++ dan berkecil hati untuk alasan yang sama seperti std::list
(penggunaan cache yang buruk).
Namun, dengan merujuk pada judul bagian ini ("memori bersama / bisa berubah"), Rust memiliki satu perbedaan dengan C ++: Sangat mendorong memori itu "dibagi-pakai XOR bersama", yaitu, bahwa memori tidak pernah dibagi dan dapat diubah pada saat yang sama. waktu. Mutasi memori yang Anda inginkan "dalam privasi utas Anda sendiri", jadi untuk berbicara. Bandingkan ini dengan C ++ di mana memori yang dapat dibagikan bersama adalah opsi default dan banyak digunakan.
Sementara paradigma shared-xor-bisa berubah sangat penting untuk perbedaan di bawah ini, itu juga merupakan paradigma pemrograman yang sangat berbeda yang membutuhkan waktu untuk terbiasa, dan yang menempatkan batasan yang signifikan. Kadang-kadang seseorang harus memilih keluar dari paradigma ini, misalnya, dengan tipe atomik ( AtomicUsize
adalah inti dari memori yang dapat ditukar bersama). Perhatikan bahwa kunci juga mematuhi aturan shared-xor-bisa berubah, karena aturan ini secara bersamaan membaca dan menulis (sementara satu utas menulis, tidak ada utas lain yang dapat membaca atau menulis).
Non-perbedaan: Ras data adalah perilaku yang tidak terdefinisi (UB)
Jika Anda memicu perlombaan data dalam kode Rust, permainan berakhir, seperti halnya di C ++. Semua taruhan dimatikan dan kompiler dapat melakukan apapun yang diinginkan.
Namun, itu adalah jaminan sulit bahwa kode Rust yang aman tidak memiliki ras data (atau UB dalam hal ini). Ini meluas ke bahasa inti dan ke perpustakaan standar. Jika Anda dapat menulis program Rust yang tidak menggunakan unsafe
(termasuk di perpustakaan pihak ketiga tetapi tidak termasuk perpustakaan standar) yang memicu UB, maka itu dianggap sebagai bug dan akan diperbaiki (ini sudah terjadi beberapa kali). Hal ini tentu saja sangat kontras dengan C ++, di mana sepele untuk menulis program dengan UB.
Perbedaan: Disiplin penguncian yang ketat
Tidak seperti C ++, kunci di Rust ( std::sync::Mutex
, std::sync::RwLock
, dll) memiliki data itu melindungi. Alih-alih mengambil kunci dan kemudian memanipulasi beberapa memori bersama yang terkait dengan kunci hanya dalam dokumentasi, data bersama tidak dapat diakses saat Anda tidak memegang kunci. Seorang penjaga RAII menjaga kunci dan secara bersamaan memberikan akses ke data yang terkunci (banyak ini dapat diimplementasikan oleh C ++, tetapi tidak dengan std::
kunci). Sistem seumur hidup memastikan bahwa Anda tidak dapat terus mengakses data setelah Anda melepaskan kunci (jatuhkan penjaga RAII).
Tentu saja Anda dapat memiliki kunci yang tidak berisi data berguna ( Mutex<()>
), dan hanya berbagi beberapa memori tanpa secara eksplisit mengaitkannya dengan kunci itu. Namun, memiliki memori bersama yang berpotensi tidak disinkronkan memerlukan unsafe
.
Perbedaan: Pencegahan pembagian yang tidak disengaja
Meskipun Anda dapat berbagi memori, Anda hanya berbagi ketika Anda secara eksplisit memintanya. Misalnya, ketika Anda menggunakan pesan yang lewat (misalnya saluran dari std::sync
), sistem seumur hidup memastikan bahwa Anda tidak menyimpan referensi ke data setelah Anda mengirimnya ke utas lain. Untuk berbagi data di balik kunci, Anda membuat kunci secara eksplisit dan memberikannya ke utas lainnya. Untuk berbagi memori yang tidak disinkronkan dengan unsafe
Anda, Anda harus menggunakan unsafe
.
Ini mengikat ke poin berikutnya:
Perbedaan: pelacakan thread-safety
Sistem tipe Rust melacak beberapa gagasan tentang keamanan benang. Secara khusus, Sync
sifat menunjukkan tipe yang dapat dibagikan oleh beberapa utas tanpa risiko ras data, sementara Send
menandai sifat yang dapat dipindahkan dari satu utas ke yang lain. Ini diberlakukan oleh kompiler sepanjang program, dan dengan demikian perancang perpustakaan berani membuat optimasi yang akan sangat berbahaya tanpa pemeriksaan statis ini. Misalnya, C ++ std::shared_ptr
yang selalu menggunakan operasi atom untuk memanipulasi jumlah referensi, untuk menghindari UB jika shared_ptr
kebetulan digunakan oleh beberapa utas. Rust memiliki Rc
dan Arc
, yang hanya berbeda dalam yang Rc
menggunakan operasi refcount non-atom dan tidak aman untuk thread (yaitu tidak mengimplementasikan Sync
atau Send
) sementara Arc
sangat miripshared_ptr
(dan mengimplementasikan kedua sifat).
Perhatikan bahwa jika suatu tipe tidak digunakan unsafe
untuk mengimplementasikan sinkronisasi secara manual, ada atau tidak adanya sifat disimpulkan dengan benar.
Perbedaan: Aturan yang sangat ketat
Jika kompiler tidak dapat benar-benar yakin bahwa beberapa kode bebas dari ras data dan UB lainnya, itu tidak akan dikompilasi, titik . Aturan-aturan dan alat-alat lain tersebut dapat membuat Anda cukup jauh, tetapi cepat atau lambat Anda akan ingin melakukan sesuatu yang benar, tetapi untuk alasan halus yang luput dari pemberitahuan kompiler. Ini bisa menjadi struktur data bebas kunci yang rumit, tetapi bisa juga sesuatu yang biasa seperti "Saya menulis ke lokasi acak dalam array bersama tetapi indeks dihitung sedemikian rupa sehingga setiap lokasi ditulis hanya oleh satu utas".
Pada titik itu Anda dapat menggigit peluru dan menambahkan sedikit sinkronisasi yang tidak perlu, atau Anda menyusun ulang kode sedemikian rupa sehingga kompiler dapat melihat kebenarannya (sering dapat dilakukan, kadang-kadang sangat sulit, kadang-kadang tidak mungkin), atau Anda memasukkan ke dalam unsafe
kode. Tetap saja, ini overhead mental ekstra, dan Rust tidak memberi Anda jaminan atas kebenaran unsafe
kode.
Perbedaan: Lebih sedikit alat
Karena perbedaan yang disebutkan di atas, di Rust jauh lebih jarang seseorang menulis kode yang mungkin memiliki ras data (atau penggunaan setelah bebas, atau bebas ganda, atau ...). Walaupun ini bagus, itu memiliki efek samping yang disayangkan bahwa ekosistem untuk melacak kesalahan seperti itu bahkan lebih terbelakang daripada yang diperkirakan karena kaum muda dan ukuran kecil masyarakat.
Walaupun alat-alat seperti valgrind dan LLVM's thread sanitizer pada prinsipnya dapat diterapkan pada kode Rust, apakah ini benar-benar berfungsi namun bervariasi dari satu alat ke alat lainnya (dan bahkan alat yang bekerja mungkin sulit untuk dipasang, terutama karena Anda mungkin tidak menemukan apa pun yang sesuai dengan keinginan Anda). Sumber daya -tanggal tentang cara melakukannya). Itu tidak benar-benar membantu bahwa Rust saat ini tidak memiliki spesifikasi nyata dan khususnya model memori formal.
Singkatnya, menulis unsafe
kode Rust dengan benar lebih sulit daripada menulis kode C ++ dengan benar, meskipun kedua bahasa secara kasar sebanding dalam hal kemampuan dan risiko. Tentu saja ini harus dipertimbangkan terhadap fakta bahwa program Rust yang khas hanya akan mengandung sebagian kecil unsafe
kode, sedangkan program C ++, yah, sepenuhnya C ++.