Saya telah bekerja pada implementasi runtime JavaScript multi-threaded selama seminggu terakhir. Saya memiliki bukti konsep yang dibuat dalam C ++ menggunakan JavaScriptCore dan meningkatkan.
Arsitekturnya sederhana: ketika runtime selesai mengevaluasi skrip utama, ia meluncurkan dan bergabung dengan thread-pool, yang mulai memilih tugas dari antrian prioritas bersama, jika dua tugas mencoba mengakses variabel secara bersamaan, ia ditandai atom dan mereka bersaing untuk akses .
Masalahnya adalah ketika saya menunjukkan desain ini ke seorang programmer JavaScript saya mendapatkan umpan balik yang sangat negatif, dan saya tidak tahu mengapa. Bahkan secara pribadi, mereka semua mengatakan bahwa JavaScript dimaksudkan untuk berurutan tunggal, bahwa perpustakaan yang ada harus ditulis ulang, dan bahwa gremlin akan menelurkan dan memakan setiap makhluk hidup jika saya terus mengerjakan ini.
Saya awalnya memiliki implementasi coroutine asli (menggunakan konteks boost) di tempat juga, tetapi saya harus membuangnya (JavaScriptCore sangat bertele-tele tentang stack), dan saya tidak ingin mengambil risiko kemarahan mereka sehingga saya memutuskan untuk tidak menyebutkannya.
Bagaimana menurut anda? Apakah JavaScript harus berurutan tunggal, dan haruskah dibiarkan sendiri? Mengapa semua orang menentang gagasan runtime JavaScript bersamaan?
Sunting: Proyek ini sekarang ada di GitHub , bereksperimenlah sendiri dan beri tahu saya apa yang Anda pikirkan.
Berikut ini adalah gambar janji yang berjalan di semua core CPU secara paralel tanpa pertentangan:
sumber
Jawaban:
1) Multithreading sangat sulit, dan sayangnya cara Anda menyajikan ide ini sejauh ini menyiratkan bahwa Anda terlalu meremehkan betapa sulitnya itu.
Saat ini, sepertinya Anda hanya "menambahkan utas" ke bahasa tersebut dan mengkhawatirkan cara memperbaikinya dan performan nanti. Khususnya:
Menambahkan utas ke Javascript tanpa "solusi untuk masalah sinkronisasi" akan seperti menambahkan bilangan bulat ke Javascript tanpa "solusi untuk masalah penambahan". Ini sangat mendasar untuk sifat masalah yang pada dasarnya tidak ada gunanya bahkan membahas apakah multithreading layak ditambahkan tanpa solusi spesifik dalam pikiran, tidak peduli seberapa buruk kita inginkan.
Plus, membuat semua variabel atom adalah hal yang cenderung membuat program multithread berkinerja lebih buruk daripada rekannya yang singlethreaded, yang membuatnya lebih penting untuk benar-benar menguji kinerja pada program yang lebih realistis dan melihat apakah Anda memperoleh sesuatu atau tidak.
Juga tidak jelas bagi saya apakah Anda mencoba menyembunyikan utas dari programmer node.js atau jika Anda berencana untuk mengeksposnya di beberapa titik, secara efektif membuat dialek Javascript baru untuk pemrograman multithreaded. Kedua opsi tersebut berpotensi menarik, tetapi sepertinya Anda belum memutuskan yang mana yang Anda tuju.
Jadi saat ini, Anda meminta programmer untuk mempertimbangkan beralih dari lingkungan singlethreaded ke lingkungan multithread baru yang tidak memiliki solusi untuk masalah sinkronisasi dan tidak ada bukti yang meningkatkan kinerja dunia nyata, dan tampaknya tidak ada rencana untuk menyelesaikan masalah tersebut.
Mungkin itulah sebabnya orang tidak menganggapmu serius.
2) Kesederhanaan dan kekokohan dari loop peristiwa tunggal adalah keuntungan besar .
Programmer Javascript tahu bahwa bahasa Javascript "aman" dari kondisi ras dan bug lain yang sangat berbahaya yang mengganggu semua pemrograman multithreaded. Fakta bahwa mereka membutuhkan argumen yang kuat untuk meyakinkan mereka agar menyerah bahwa keselamatan tidak membuat mereka berpikiran tertutup, itu membuat mereka bertanggung jawab.
Kecuali Anda bisa mempertahankan keamanan itu, siapa pun yang mungkin ingin beralih ke node multithreaded. Mungkin akan lebih baik beralih ke bahasa seperti Go yang dirancang dari bawah ke atas untuk aplikasi multithreaded.
3) Javascript sudah mendukung "latar belakang utas" (WebWorkers) dan pemrograman asinkron tanpa secara langsung memaparkan manajemen utas kepada programmer.
Fitur-fitur tersebut sudah menyelesaikan banyak kasus penggunaan umum yang memengaruhi programmer Javascript di dunia nyata, tanpa meninggalkan keamanan loop peristiwa tunggal.
Apakah Anda memiliki kasus penggunaan tertentu dalam pikiran bahwa fitur-fitur ini tidak menyelesaikan, dan bahwa programmer Javascript menginginkan solusi? Jika demikian, itu akan menjadi ide yang baik untuk menyajikan node.js multithreaded Anda dalam konteks kasus penggunaan tertentu.
PS Apa yang meyakinkan saya untuk mencoba beralih ke implementasi node.js multithreaded?
Tulis program non-sepele dalam Javascript / node.js yang menurut Anda akan mendapat manfaat dari multithreading asli. Lakukan tes kinerja pada program sampel ini dalam simpul normal dan simpul multithreaded Anda. Tunjukkan pada saya bahwa versi Anda meningkatkan kinerja runtime, responsif, dan penggunaan beberapa core hingga tingkat yang signifikan, tanpa memperkenalkan bug atau ketidakstabilan apa pun.
Setelah Anda selesai melakukannya, saya pikir Anda akan melihat orang-orang jauh lebih tertarik pada ide ini.
sumber
Hanya menebak di sini untuk menunjukkan masalah dalam pendekatan Anda. Saya tidak dapat mengujinya terhadap implementasi nyata karena tidak ada tautan di mana pun ...
Saya akan mengatakan itu karena invarian tidak selalu dinyatakan oleh nilai satu variabel, dan 'satu variabel' tidak cukup untuk menjadi lingkup kunci dalam kasus umum. Sebagai contoh, bayangkan kita memiliki invarian yang
a+b = 0
(saldo bank dengan dua akun). Dua fungsi di bawah ini memastikan bahwa invarian selalu diadakan di akhir setiap fungsi (unit eksekusi di JS single-threaded).Sekarang, di dunia multithreaded Anda, apa yang terjadi ketika dua utas mengeksekusi
withdraw
dandeposit
pada saat yang sama? Terima kasih, Murphy ...(Anda mungkin memiliki kode yang memperlakukan + = dan - = secara khusus, tetapi itu tidak membantu. Pada titik tertentu, Anda akan memiliki status lokal dalam suatu fungsi, dan tanpa cara untuk 'mengunci' dua variabel pada saat yang bersamaan invarian Anda akan dilanggar.)
EDIT: Jika kode Anda secara semantik setara dengan kode Go di https://gist.github.com/thriqon/f94c10a45b7e0bf656781b0f4a07292a , komentar saya akurat ;-)
sumber
Satu dekade yang lalu, Brendan Eich (penemu JavaScript) menulis sebuah esai berjudul Threads Suck , yang jelas merupakan salah satu dari sedikit dokumen kanonik mitologi desain JavaScript.
Apakah itu benar adalah pertanyaan lain, tapi saya pikir itu memiliki pengaruh besar pada bagaimana komunitas JavaScript berpikir tentang concurrency.
sumber
Akses atom tidak diterjemahkan ke dalam perilaku thread-safe.
Salah satu contoh adalah ketika struktur data global perlu tidak valid selama pembaruan seperti mengulang hashmap (ketika menambahkan properti ke objek misalnya) atau menyortir array global. Selama waktu itu Anda tidak dapat mengizinkan utas lain mengakses variabel. Ini pada dasarnya berarti bahwa Anda perlu mendeteksi seluruh siklus baca-perbarui-tulis dan menguncinya. Jika pembaruan itu tidak sepele, itu akan berakhir pada penghentian wilayah masalah.
Javascript telah berurutan tunggal dan kotak pasir dari awal dan semua kode ditulis dengan asumsi ini.
Ini memiliki keuntungan besar sehubungan dengan konteks yang terisolasi dan membiarkan 2 konteks terpisah berjalan di utas yang berbeda. Saya juga berarti bahwa orang yang menulis javascript tidak perlu tahu bagaimana menghadapi kondisi ras dan berbagai pitfals multi-thread lainnya.
sumber
Apakah pendekatan Anda akan secara signifikan meningkatkan kinerja?
Diragukan. Anda benar-benar perlu membuktikan ini.
Apakah pendekatan Anda akan membuatnya lebih mudah / lebih cepat untuk menulis kode?
Jelas tidak, kode multithreaded berkali-kali lebih sulit untuk mendapatkan yang benar daripada kode single threaded.
Apakah pendekatan Anda akan lebih kuat?
Kebuntuan, kondisi balapan dll. Adalah mimpi buruk untuk diperbaiki.
sumber
Implementasi Anda bukan hanya tentang memperkenalkan konkurensi, melainkan tentang memperkenalkan cara spesifik untuk mengimplementasikan konkurensi yaitu konkurensi dengan status yang dapat ditukar pakai bersama. Sepanjang sejarah orang telah menggunakan jenis konkurensi dan ini telah menyebabkan banyak jenis masalah. Ofcourse Anda dapat membuat program sederhana yang bekerja sempurna dengan menggunakan konkurensi keadaan bersama yang dapat ditukar, tetapi ujian sebenarnya dari mekanisme apa pun bukanlah apa yang dapat ia lakukan tetapi dapat mengukurnya saat program menjadi kompleks dan semakin banyak fitur ditambahkan ke program. Ingat perangkat lunak bukanlah hal statis yang Anda bangun sekali dan selesai dengan itu, melainkan terus berkembang dari waktu ke waktu dan jika ada mekanisme atau konsep yang bisa '
Anda dapat melihat model konkurensi lainnya (misal: pesan yang lewat) untuk membantu Anda mengetahui manfaat apa yang diberikan oleh model-model itu.
sumber
Ini dibutuhkan. Kurangnya mekanisme konkurensi tingkat rendah di simpul js membatasi aplikasinya dalam bidang seperti matematika dan bioinformatika, dll. Selain itu, konkurensi dengan utas tidak selalu bertentangan dengan model konsurensi default yang digunakan dalam simpul. Ada semantik terkenal untuk threading dalam lingkungan dengan loop peristiwa utama, seperti kerangka ui (dan nodejs), dan mereka pasti terlalu rumit untuk sebagian besar situasi mereka masih memiliki kegunaan yang valid.
Tentu, aplikasi web rata-rata Anda tidak akan memerlukan utas, tetapi cobalah melakukan sesuatu yang sedikit kurang konvensional, dan kurangnya primitif konkurensi tingkat rendah suara dengan cepat akan menggerakkan Anda ke sesuatu yang menawarkannya.
sumber
Saya sangat percaya itu karena itu ide yang berbeda dan kuat. Anda menentang sistem kepercayaan. Barang-barang menjadi diterima atau populer melalui jaringan tidak memengaruhi berdasarkan prestasi. Juga tidak ada yang mau beradaptasi dengan tumpukan baru. Orang secara otomatis menolak hal-hal yang terlalu berbeda.
Jika Anda dapat menemukan cara untuk membuatnya menjadi modul npm reguler yang sepertinya tidak mungkin, maka Anda mungkin membuat beberapa orang menggunakannya.
sumber