Terokai teori di sebalik gelung pemprosesan acara dalam Node.js
P粉564192131
P粉564192131 2024-04-01 19:35:24
0
1
475

Saya sedang melihat intipati ini menerangkan algoritma traversal fail dalam JavaScript

// ES6 version using asynchronous iterators, compatible with node v10.0+

const fs = require("fs");
const path = require("path");

async function* walk(dir) {
    for await (const d of await fs.promises.opendir(dir)) {
        const entry = path.join(dir, d.name);
        if (d.isDirectory()) yield* walk(entry);
        else if (d.isFile()) yield entry;
    }
}

// Then, use it with a simple async for loop
async function main() {
    for await (const p of walk('/tmp/'))
        console.log(p)
}

Saya terpesona dengan dorongan (bahasa, bukan pengarang) untuk menjejalkan async/menunggu ke setiap celah algoritma. Saya tidak tahu banyak tentang seni bina Node.js, tetapi saya menganggap terdapat beberapa niat di sebalik ciri yang sangat tidak segerak? Ini sangat mengelirukan dan baru kepada saya yang terutamanya terdedah kepada model benang/proses C/C++ prosedur deklaratif. Apa yang saya ingin tahu bukan "apakah modelnya" atau "adakah ia lebih baik", kerana orang ramai mungkin mempunyai pendapat, tetapi "apakah idea yang mendorong ketidaksegerakan Ini adalah keperluan pelayar untuk responsif terhadap tugas umum A legasi?" kecekapan?

Soalan saya ialah "Mengapa begitu banyak ketidaksegerakan?". Saya tidak mencari pendapat, tetapi seseorang yang memahami sejarah dan evolusi Node.js atau JavaScript untuk menerangkan seni binanya.

Isi penting: https://gist.github.com/lovasoa/8691344

P粉564192131
P粉564192131

membalas semua(1)
P粉328911308

Nah, pada tahap yang tinggi, bahagian pertama ayat itu dan bahagian kedua ayat itu bercanggah. Jika pelayan tidak cekap, maka ia tidak akan dapat bertindak balas dengan betul kepada sekumpulan permintaan pelanggan yang tiba pada masa yang sama. Oleh itu, anda ingin menjadikan pelayan anda lebih cekap supaya ia boleh responsif kepada permintaan pelanggan yang mungkin.


Sekarang, kita perlu kembali beberapa langkah dan memahami apa sebenarnya yang berlaku dalam kod yang anda tunjukkan. Pertama, walaupun bahasa itu adalah Javascript, logik teras kod ini dan cara ia menggunakan asyncawait dan penjana bukan hanya kerana Javascript bahasa. Ini adalah kerana persekitaran khusus di mana Javascript dijalankan, dalam kes ini nodejs.

Persekitaran ini menggunakan gelung acara dan menjalankan satu utas Javascript. Benang sistem pengendalian lain digunakan untuk pelbagai perkara sistem dan beberapa pelaksanaan perpustakaan, tetapi apabila nodejs menjalankan Javascript anda, ia hanya menjalankan satu bahagian Javascript pada satu masa (benang tunggal).

Pada masa yang sama, apabila anda mereka bentuk pelayan, anda mahu ia dapat bertindak balas kepada sejumlah besar permintaan masuk. Anda tidak mahu ia perlu memproses satu permintaan dan meminta semua permintaan lain menunggu sehingga permintaan pertama selesai sebelum memulakan permintaan seterusnya. Walau bagaimanapun, model gelung peristiwa nodejs tidak menggunakan berbilang benang dan oleh itu tidak menjalankan berbilang pengendali permintaan secara langsung pada masa yang sama.

Penyelesaian yang digunakan oleh nodejs datang daripada fakta bahawa untuk pelbagai pengendali permintaan pelayan, aktiviti utama dan perkara yang menghabiskan kebanyakan masa mengendalikan permintaan ialah I/O (seperti rangkaian, fail I/O atau pangkalan data) /O). Ini adalah operasi peringkat rendah yang mempunyai pelaksanaan sendiri (bukan Javascript).

Oleh itu, ia menggunakan model tak segerak untuk semua operasi I/O. Pelayan yang ditulis dengan baik boleh memulakan operasi I/O tak segerak, dan semasa ia diproses (bukan dalam kod yang dijalankan dalam penterjemah Nodejs itu sendiri), penterjemah dan gelung acara NodeJS bebas melakukan perkara lain dan mengendalikan permintaan lain. Beberapa ketika kemudian, apabila operasi tak segerak itu selesai, acara dimasukkan ke dalam gelung peristiwa, dan apabila jurubahasa melengkapkan apa-apa operasi yang sedang dilakukannya, ia boleh memproses hasil operasi tak segerak dan meneruskan operasi.

Dengan cara ini, Javascript hanya dilaksanakan dalam satu utas, tetapi banyak permintaan masuk boleh "diproses" pada masa yang sama.

Ya, ini adalah model yang sama sekali berbeza daripada model benang C/C++ lama. Anda sama ada mempelajari model berbeza ini untuk menulis kod pelayan yang cekap dan berkesan dalam Nodejs, atau anda tidak. Jika anda ingin kekal dengan model lama, kemudian pilih persekitaran berbeza yang menjalankan pengendali permintaan dalam benang (Java, C++, dll.) dan bertujuan untuk melakukannya dengan baik (dengan reka bentuk yang berkaitan dan overhed ujian sudah tentu ) ditulis dengan betul dan diuji dengan teliti untuk semua konkurensi berbilang benang).

Salah satu perkara hebat tentang model nodejs ialah ia kurang terdedah kepada banyak isu konkurensi yang dimiliki oleh model pelaksanaan berbilang benang. Model Nodejs juga mempunyai beberapa kelemahan yang kadangkala memerlukan penyelesaian. Sebagai contoh, jika anda mempunyai kod intensif CPU dalam pengendali permintaan yang ditulis dalam Javascript, ini masih akan mengganggu keadaan dan anda perlu mencari cara untuk mengalihkan kod intensif CPU keluar dari gelung acara utama dan ke yang berbeza thread , atau proses (mungkin juga baris gilir kerja). Walau bagaimanapun, I/O semuanya tidak segerak dan boleh kekal pada utas utama tanpa menyebabkan sebarang masalah.

Semakin sedikit kod yang perlu ada dalam urutan serentak yang berasingan, semakin sedikit pepijat serentak yang mungkin anda hadapi dan kod tersebut lebih mudah untuk diuji sepenuhnya.

Nah, anda mahukan gelung kerana anda cuba mengulung sesuatu. Anda ingin menggunakan operasi async dalam gelung acara apabila anda tidak mahu menyekat gelung acara atau apabila ini adalah satu-satunya jenis operasi yang anda perlu menyelesaikan tugasan (seperti melakukan carian dalam pangkalan data).

Menggunakan operasi tak segerak bukanlah tentang mengoptimumkan sesuatu. Ini mengenai reka bentuk teras untuk menulis kod pelayan yang baik dan tidak menyekat gelung acara. Dan, sebenarnya, antara muka yang mungkin dalam nodejs (seperti antara muka pangkalan data atau antara muka rangkaian) hanya menyediakan antara muka tak segerak.

Cara anda bertanya soalan ini menunjukkan bahawa anda akan mendapat manfaat daripada memahami dengan lebih baik seni bina teras Nodejs dan membaca lebih lanjut tentang cara gelung acara berfungsi dan cara operasi I/O tak segerak berfungsi.

Pertama sekali, jika anda menggunakan API tak segerak (seperti rangkaian atau pangkalan data), anda tiada pilihan. Anda akan mereka bentuk kod tak segerak untuk menggunakan API ini. Jika anda mempunyai pilihan antara menggunakan API tak segerak atau segerak (sama seperti yang anda lakukan dengan akses sistem fail dalam Node.js), maka anda boleh memilih sama ada untuk menyekat gelung peristiwa pada setiap panggilan API atau tidak. Jika anda menyekat gelung acara, anda akan memudaratkan skalabiliti dan responsif pelayan anda dengan serius.


Contoh kod khusus ini benar-benar cuba menggunakan sink dapur ciri bahasa async dalam pelaksanaan yang sama seperti asyncawait、生成器和 yield . Saya biasanya tidak melakukan ini. Inti pelaksanaan ini adalah untuk dapat mencipta antara muka yang boleh digunakan dengan mudah seperti ini:

for await (const p of walk('/tmp/')) {
    ...
}

Dan walk() 的内部是异步的。此实现向 API 用户隐藏了几乎所有异步实现的复杂性,这使得 API 更易于编码。通过将单个 await letakkan di tempat yang betul, pengguna API boleh kod hampir serentak. Tujuan ciri bahasa Javascript ini (janji, async, await, generator, dll.) adalah untuk menjadikan operasi tak segerak lebih mudah untuk dikodkan.

Kelebihan model gelung acara

Mudah diprogramkan. Anda biasanya tidak perlu berurusan dengan isu konkurensi apabila mengakses data kongsi daripada utas, kerana semua Javascript berjalan dalam urutan yang sama, jadi semua akses data kongsi datang daripada urutan yang sama. Anda tidak memerlukan mutex untuk mengakses data kongsi. Anda tidak menghadapi sebarang risiko kebuntuan dengan mutex ini.

Ralat yang lebih sedikit. Mengakses data awam daripada benang adalah lebih sukar untuk menulis kod bebas pepijat. Jika tidak ditulis dengan sempurna, kod itu mungkin tertakluk kepada syarat perlumbaan atau kekurangan perlindungan serentak. Selain itu, keadaan perlumbaan ini selalunya sukar untuk diuji dan mungkin tidak menjadi jelas sehingga pelayan anda berada di bawah beban berat, dan walaupun begitu ia tidak mudah untuk dihasilkan semula.

Skala yang lebih tinggi (dalam beberapa kes). Untuk kod yang terutamanya terikat I/O, model gelung peristiwa koperasi boleh membawa kepada kebolehskalaan yang lebih besar. Ini kerana setiap permintaan dalam pemprosesan tidak menghasilkan urutan sistem pengendalian yang berasingan dan overhed tambahannya. Sebaliknya, terdapat hanya sedikit keadaan aplikasi, biasanya dalam penutupan yang berkaitan dengan menunggu panggilan balik atau janji seterusnya.

Artikel tentang pengaturcaraan gelung acara

Mengapa kanak-kanak yang hebat menggunakan gelung acara - Ini berlaku mengenai penggunaan gelung acara dalam pengaturcaraan Java, tetapi perbincangan itu terpakai kepada mana-mana persekitaran

Contoh benang dan acara

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan