Node memiliki paradigma yang sama sekali berbeda dan setelah ditangkap dengan benar, akan lebih mudah untuk melihat cara berbeda dalam memecahkan masalah. Anda tidak perlu banyak utas dalam aplikasi Node (1) karena Anda memiliki cara berbeda untuk melakukan hal yang sama. Anda membuat banyak proses; tetapi sangat sangat berbeda dari, misalnya bagaimana mpm Prefork Server Web Apache lakukan.
Untuk saat ini, anggap saja kita hanya memiliki satu inti CPU dan kita akan mengembangkan aplikasi (dengan cara Node) untuk melakukan beberapa pekerjaan. Tugas kita adalah memproses file besar yang menjalankan isinya byte-by-byte. Cara terbaik untuk perangkat lunak kami adalah memulai pekerjaan dari awal file, ikuti byte-by-byte sampai akhir.
- Hei, Hasan, saya kira Anda adalah seorang pemula atau sekolah yang sangat tua dari zaman Kakek saya !!! Mengapa Anda tidak membuat beberapa utas dan membuatnya lebih cepat?
- Oh, kami hanya memiliki satu inti CPU.
-- Terus? Buat beberapa utas, lebih cepat!
- Ini tidak bekerja seperti itu. Jika saya membuat utas, saya akan membuatnya lebih lambat. Karena saya akan menambahkan banyak overhead ke sistem untuk beralih antar utas, mencoba memberi mereka waktu yang cukup, dan di dalam proses saya, mencoba berkomunikasi di antara utas ini. Selain semua fakta ini, saya juga harus memikirkan tentang bagaimana saya akan membagi satu pekerjaan menjadi beberapa bagian yang dapat dilakukan secara paralel.
- Oke oke, saya melihat Anda miskin. Ayo gunakan komputer saya, ini memiliki 32 inti!
- Wow, kamu luar biasa temanku, terima kasih banyak. Saya menghargainya!
Lalu kami kembali bekerja. Sekarang kami memiliki 32 inti cpu berkat teman kaya kami. Aturan yang harus kita patuhi baru saja berubah. Sekarang kami ingin memanfaatkan semua kekayaan yang kami berikan ini.
Untuk menggunakan banyak inti, kita perlu menemukan cara untuk membagi pekerjaan kita menjadi beberapa bagian yang dapat kita tangani secara paralel. Jika bukan Node, kami akan menggunakan utas untuk ini; 32 utas, satu untuk setiap inti cpu. Namun, karena kami memiliki Node, kami akan membuat 32 proses Node.
Thread dapat menjadi alternatif yang baik untuk proses Node, bahkan mungkin cara yang lebih baik; tetapi hanya dalam jenis pekerjaan tertentu yang pekerjaannya sudah ditentukan dan kami memiliki kendali penuh atas cara menanganinya. Selain ini, untuk setiap jenis masalah lain di mana pekerjaan berasal dari luar dengan cara yang tidak dapat kami kendalikan dan kami ingin menjawab secepat mungkin, cara Node sangat unggul.
- Hei, Hasan, apakah kamu masih bekerja single-threaded? Ada apa denganmu, bung? Saya baru saja memberikan apa yang Anda inginkan. Anda tidak punya alasan lagi. Buat utas, buat itu berjalan lebih cepat.
- Saya telah membagi pekerjaan menjadi beberapa bagian dan setiap proses akan mengerjakan salah satu bagian ini secara paralel.
- Mengapa Anda tidak membuat utas?
- Maaf, menurutku itu tidak bisa digunakan. Anda dapat mengambil komputer Anda jika Anda mau?
- Tidak oke, saya keren, saya hanya tidak mengerti mengapa Anda tidak menggunakan utas?
- Terima kasih untuk komputernya. :) Saya sudah membagi pekerjaan menjadi beberapa bagian dan saya membuat proses untuk mengerjakan bagian-bagian ini secara paralel. Semua inti CPU akan digunakan sepenuhnya. Saya bisa melakukan ini dengan utas alih-alih proses; tetapi Node memiliki cara ini dan bos saya Parth Thakkar ingin saya menggunakan Node.
- Oke, beri tahu saya jika Anda membutuhkan komputer lain. : hal
Jika saya membuat 33 proses, alih-alih 32, penjadwal sistem operasi akan menjeda utas, memulai yang lain, menjeda setelah beberapa siklus, memulai yang lain lagi ... Ini adalah pengeluaran tambahan yang tidak perlu. Saya tidak mau itu. Faktanya, pada sistem dengan 32 core, saya bahkan tidak ingin membuat persis 32 proses, 31 bisa lebih bagus . Karena bukan hanya aplikasi saya yang akan bekerja pada sistem ini. Meninggalkan sedikit ruang untuk hal-hal lain bisa menjadi baik, terutama jika kita memiliki 32 kamar.
Saya yakin kita berada di halaman yang sama sekarang tentang penggunaan prosesor sepenuhnya untuk tugas-tugas intensif CPU .
- Hmm, Hasan, saya minta maaf karena telah sedikit mengejek Anda. Saya yakin saya memahami Anda lebih baik sekarang. Tapi masih ada sesuatu yang saya perlu penjelasannya: Apa yang paling menarik tentang menjalankan ratusan utas? Saya membaca di mana-mana bahwa utas jauh lebih cepat dibuat dan bodoh daripada proses bercabang? Anda membagi proses alih-alih utas dan Anda pikir itu adalah yang tertinggi yang akan Anda dapatkan dengan Node. Lalu apakah Node tidak sesuai untuk jenis pekerjaan ini?
- Jangan khawatir, aku juga keren. Semua orang mengatakan hal-hal ini jadi saya pikir saya sudah terbiasa mendengarnya.
- Jadi? Node tidak bagus untuk ini?
- Node sangat bagus untuk ini meskipun utas juga bisa bagus. Adapun overhead pembuatan thread / proses; pada hal-hal yang sering Anda ulangi, setiap milidetik penting. Namun, saya hanya membuat 32 proses dan itu akan memakan sedikit waktu. Itu hanya akan terjadi sekali. Tidak akan ada bedanya.
- Kapan saya ingin membuat ribuan utas?
- Anda tidak pernah ingin membuat ribuan utas. Namun, pada sistem yang melakukan pekerjaan yang datang dari luar, seperti server web yang memproses permintaan HTTP; jika Anda menggunakan utas untuk setiap permintaan, Anda akan membuat banyak utas, banyak di antaranya.
- Node berbeda sih? Baik?
-- Ya persis. Di sinilah Node benar-benar bersinar. Seperti utas jauh lebih ringan daripada proses, panggilan fungsi jauh lebih ringan daripada utas. Node memanggil fungsi, alih-alih membuat utas. Dalam contoh server web, setiap permintaan masuk menyebabkan panggilan fungsi.
-- Hmm menarik; tetapi Anda hanya dapat menjalankan satu fungsi pada saat yang sama jika Anda tidak menggunakan banyak utas. Bagaimana ini bisa bekerja ketika banyak permintaan tiba di server web pada saat yang bersamaan?
- Anda benar sekali tentang cara menjalankan fungsi, satu per satu, tidak pernah dua fungsi secara paralel. Maksud saya dalam satu proses, hanya satu cakupan kode yang berjalan pada satu waktu. OS Scheduler tidak datang dan menjeda fungsi ini dan beralih ke fungsi lain, kecuali jika menjeda proses untuk memberikan waktu ke proses lain, bukan utas lain dalam proses kami. (2)
- Lalu bagaimana sebuah proses menangani 2 permintaan sekaligus?
- Sebuah proses dapat menangani puluhan ribu permintaan dalam satu waktu selama sistem kami memiliki cukup sumber daya (RAM, Jaringan, dll.). Bagaimana fungsi-fungsi itu berjalan adalah PERBEDAAN KUNCI.
- Hmm, haruskah aku bersemangat sekarang?
- Mungkin :) Node menjalankan loop melalui antrian. Dalam antrian ini adalah pekerjaan kita, yaitu panggilan yang kita mulai untuk memproses permintaan yang masuk. Poin terpenting di sini adalah cara kami mendesain fungsi untuk dijalankan. Alih-alih mulai memproses permintaan dan membuat pemanggil menunggu hingga kami menyelesaikan pekerjaan, kami dengan cepat mengakhiri fungsi kami setelah melakukan sejumlah pekerjaan yang dapat diterima. Ketika kita sampai pada titik di mana kita perlu menunggu komponen lain untuk melakukan beberapa pekerjaan dan mengembalikan nilai kepada kita, alih-alih menunggu itu, kita cukup menyelesaikan fungsi kita dengan menambahkan sisa pekerjaan ke antrian.
- Kedengarannya terlalu rumit?
- Tidak, tidak, saya mungkin terdengar rumit; tetapi sistemnya sendiri sangat sederhana dan sangat masuk akal.
Sekarang saya ingin berhenti mengutip dialog antara kedua pengembang ini dan menyelesaikan jawaban saya setelah contoh singkat terakhir tentang cara kerja fungsi ini.
Dengan cara ini, kami melakukan apa yang biasanya dilakukan OS Scheduler. Kami menghentikan pekerjaan kami di beberapa titik dan membiarkan panggilan fungsi lain (seperti utas lain dalam lingkungan multi-utas) berjalan sampai kami mendapatkan giliran kami lagi. Ini jauh lebih baik daripada menyerahkan pekerjaan ke OS Scheduler yang mencoba memberikan waktu yang tepat untuk setiap utas pada sistem. Kami tahu apa yang kami lakukan jauh lebih baik daripada OS Scheduler dan kami diharapkan berhenti ketika kami harus berhenti.
Di bawah ini adalah contoh sederhana di mana kami membuka file dan membacanya untuk melakukan beberapa pekerjaan pada data.
Cara Sinkron:
Open File
Repeat This:
Read Some
Do the work
Cara Asynchronous:
Open File and Do this when it is ready: // Our function returns
Repeat this:
Read Some and when it is ready: // Returns again
Do some work
Seperti yang Anda lihat, fungsi kami meminta sistem untuk membuka file dan tidak menunggu untuk dibuka. Itu selesai sendiri dengan memberikan langkah selanjutnya setelah file siap. Ketika kita kembali, Node menjalankan pemanggilan fungsi lain pada antrian. Setelah menjalankan semua fungsi, event loop berpindah ke giliran berikutnya ...
Singkatnya, Node memiliki paradigma yang sama sekali berbeda dari pengembangan multi-threaded; tetapi ini tidak berarti bahwa ia kekurangan banyak hal. Untuk pekerjaan sinkron (di mana kita dapat memutuskan urutan dan cara pemrosesan), ini berfungsi serta paralelisme multi-utas. Untuk pekerjaan yang datang dari luar seperti permintaan ke server, itu lebih baik.
(1) Kecuali Anda sedang membangun perpustakaan dalam bahasa lain seperti C / C ++ dalam hal ini Anda masih tidak membuat utas untuk membagi pekerjaan. Untuk jenis pekerjaan ini Anda memiliki dua utas, salah satunya akan melanjutkan komunikasi dengan Node sementara yang lain melakukan pekerjaan sebenarnya.
(2) Faktanya, setiap proses Node memiliki banyak utas karena alasan yang sama yang saya sebutkan di catatan kaki pertama. Namun ini tidak seperti 1000 utas melakukan pekerjaan serupa. Utas tambahan tersebut adalah untuk hal-hal seperti menerima peristiwa IO dan menangani pengiriman pesan antar-proses.
UPDATE (Sebagai balasan untuk pertanyaan bagus di komentar)
@Mark, terima kasih atas kritik yang membangun. Dalam paradigma Node, Anda tidak boleh memiliki fungsi yang membutuhkan waktu terlalu lama untuk diproses kecuali semua panggilan lain dalam antrean dirancang untuk dijalankan satu demi satu. Dalam kasus tugas yang mahal secara komputasi, jika kita melihat gambar secara lengkap, kita melihat bahwa ini bukan pertanyaan "Haruskah kita menggunakan utas atau proses?" tetapi pertanyaan tentang "Bagaimana kami dapat membagi tugas ini dengan cara yang seimbang menjadi beberapa sub-tugas yang dapat kami jalankan secara paralel menggunakan beberapa inti CPU pada sistem?" Katakanlah kita akan memproses 400 file video pada sistem dengan 8 core. Jika kita ingin memproses satu file dalam satu waktu, maka kita memerlukan sistem yang akan memproses bagian yang berbeda dari file yang sama dalam hal ini, mungkin sistem proses tunggal multi-threaded akan lebih mudah dibangun dan bahkan lebih efisien. Kita masih bisa menggunakan Node untuk ini dengan menjalankan banyak proses dan meneruskan pesan di antara mereka ketika berbagi status / komunikasi diperlukan. Seperti yang saya katakan sebelumnya, pendekatan multi-proses dengan Node adalahserta pendekatan multi-utas dalam tugas semacam ini; tapi tidak lebih dari itu. Sekali lagi, seperti yang saya katakan sebelumnya, situasi Node bersinar adalah ketika kita memiliki tugas-tugas ini yang datang sebagai input ke sistem dari berbagai sumber karena menyimpan banyak koneksi secara bersamaan jauh lebih ringan di Node dibandingkan dengan thread-per-connection atau process-per-connection. sistem.
Adapun setTimeout(...,0)
panggilan; kadang-kadang memberikan jeda selama tugas yang memakan waktu untuk memungkinkan panggilan dalam antrian memiliki bagian pemrosesan mereka dapat diperlukan. Membagi tugas dengan cara yang berbeda dapat menyelamatkan Anda dari ini; tetapi tetap saja, ini sebenarnya bukan peretasan, ini hanyalah cara kerja antrean acara. Selain itu, menggunakan process.nextTick
untuk tujuan ini jauh lebih baik karena saat Anda menggunakan setTimeout
, penghitungan dan pemeriksaan waktu yang telah berlalu akan diperlukan, sementara process.nextTick
yang sebenarnya kami inginkan adalah: "Hai tugas, kembali ke akhir antrean, Anda telah menggunakan bagian Anda! "