Rumah >hujung hadapan web >tutorial js >Contoh pelaksanaan fungsi tidur dalam nodejs_node.js

Contoh pelaksanaan fungsi tidur dalam nodejs_node.js

WBOY
WBOYasal
2016-05-16 16:07:483209semak imbas

Perkara yang paling tidak menyenangkan tentang nodej ialah sifat benang tunggalnya Ia tidak boleh melakukan banyak perkara dan prestasinya tidak cukup kuat untuk senario intensif CPU. Untuk masa yang lama, saya ingin mencari beberapa penyelesaian di bawah rangka kerja bahasa JavaScript untuk menyelesaikan masalah ketidakupayaan untuk mengendalikan benang dan prestasi yang lemah. Penyelesaian yang paling menarik perhatian saya ialah serabut, tetapi tanpa mengira gentian atau penyelesaian lain, operasi benang masih sangat janggal. Ia terlalu bergantung pada benang tambahan dan meletakkan kereta di hadapan kuda prihatin, JavaScript secara semula jadi Masalah prestasi rendah tidak dapat diselesaikan Perkara yang paling janggal ialah di bawah rangka kerja bahasa JavaScript, penghantaran mesej antara utas selalunya sangat terhad, dan objek tidak boleh dikongsi dengan benar.

Kaedah addon nodejs sudah pasti sangat baik, dengan fleksibiliti yang sangat kuat, fungsi lengkap dan prestasi kod asli. Ringkasnya, ia membenarkan nodej untuk memanggil terus modul c/c, yang merupakan mod pembangunan campuran javascript dan asli. Ia adalah perkara yang baik, mengapa tidak menggunakannya? Addon harus dianggap sebagai topik yang besar. Saya tidak mahu bercakap mengenainya secara mendalam hari ini. Kemudian laksanakan fungsi tidur dan anggap ia sebagai pengenalan.

tidur

Mengapa JavaScript tidak boleh melaksanakan tidur sebenar? Kaedah tidur mendaftarkan isyarat dengan kernel sistem pengendalian dan menghantar isyarat bangun selepas masa yang ditentukan, sementara benang itu sendiri tergantung. Pada asasnya, apabila benang tidur(1000) bermakna memberitahu sistem pengendalian: Jangan peruntukkan masa CPU kepada saya dalam masa 1000ms. Oleh itu, tidur boleh memastikan bahawa utas tidak lagi menggunakan sumber CPU apabila ia digantung. JavaScript berjalan dalam satu utas dan membatalkan konsep utas Sememangnya, tiada cara untuk menggantung dan mengganggu utas utama.

Sesetengah orang juga akan cuba menggunakan javascript untuk melaksanakan tidur, contohnya:

Salin kod Kod adalah seperti berikut:

fungsi tidur(sleepTime) {
for(var start = new Date; new Date - start <= sleepTime; ) { }
}

Ini menggunakan gelung kosong untuk menyekat perjalanan proses utama untuk melaksanakan tidur, yang jelas jauh daripada tidur sebenar.

Jadi bagaimana jika kita melaksanakan tidur sebenar?

Persediaan alam sekitar

Persekitaran pembangunan

Sesetengah blog saya telah menyatakannya sebelum ini, jadi saya akan meninggalkannya di sini: node.js npm, python 2.7, visual studio/x-code.

Alat Kompilasi

Alat kompilasi perlu menggunakan node-gyp versi yang lebih baharu disertakan dengan pustaka ini. Jika node-gyp tidak disertakan, sila laksanakan:

Salin kod Kod adalah seperti berikut:

npm install -g node-gyp

Saya tidak mempunyai tenaga untuk mengkaji ciri-ciri gyp Jika anda biasa dengan penyusun lain seperti gcc, tidak dikecualikan bahawa gyp akan mempunyai ketidakserasian, dan pilihan kompilasi serta suis juga berbeza. Adalah disyorkan untuk menulis semula kod C untuk nodejs Jika memang terdapat modul yang perlu digunakan semula, anda boleh mempertimbangkan untuk menggunakan gcc biasa untuk menyusunnya ke dalam perpustakaan pautan dinamik, kemudian tulis sejumlah kecil kod untuk menggunakan pautan dinamik. perpustakaan, dan kemudian gunakan gyp untuk menyusun bahagian kod ini untuk kegunaan nodejs.

Masukkan folder projek dan jalankan npm init untuk memulakan projek. Untuk memberitahu nodejs bahawa kita ingin membuat addon, kita perlu menambah package.json:

Salin kod Kod adalah seperti berikut:

"gyp-file": benar

Jika anda telah menggunakan gcc, maka anda mesti ingat makefile. Begitu juga, gyp juga menerangkan konfigurasi kompilasi melalui fail Fail ini adalah binding.gyp, iaitu fail json yang sangat kita kenali. gyp bukanlah fokus perbincangan kami, jadi binding.gyp tidak akan diterokai secara mendalam Kami hanya akan menumpukan pada item konfigurasi yang paling penting. Berikut ialah contoh fail binding.gyp yang ringkas tetapi lengkap:

Salin kod Kod adalah seperti berikut:

{
"sasaran": [
{
"target_name": "hello",
"sumber": [ "hello.cc" ],
"include_dirs": [
" ]
}
]
}


Lihat sahaja tiga item konfigurasi yang terlibat:

1.target_name: Menunjukkan nama modul output.
2.sources: Menunjukkan laluan kod sumber yang perlu disusun Ini ialah tatasusunan.
3.include_dirs: Menunjukkan direktori yang akan digunakan semasa proses penyusunan Fail pengepala dalam direktori ini boleh dicari dalam arahan prapenyusun #include. Cara penulisan yang agak istimewa digunakan di sini Daripada memberikan laluan sebagai pemalar rentetan, kita menjalankan nod arahan -e "require('nan')". lihat apa arahan ini keluarkan: node_modulesnan, ternyata arahan ini bermaksud untuk mengembalikan laluan perpustakaan nan.

Pengekodan C

OK, kerana kod sumber ialah hello.cc telah dikonfigurasikan, buat fail sedemikian. Terdapat masalah yang perlu diingatkan terlebih dahulu Modul c yang kita tulis akhirnya akan digunakan oleh enjin v8, jadi API, kaedah penulisan, dan lain-lain dihadkan oleh enjin v8. Versi nodej yang berbeza sebenarnya menggunakan versi enjin v8 yang berbeza, yang bermaksud bahawa sukar untuk menggunakan set kod c untuk memenuhi versi nodej yang berbeza (merujuk kepada proses penyusunan. Selepas penyusunan selesai, ia sepatutnya dapat boleh digunakan merentasi versi, tanpa pengesahan Ya.

nod 0.11 dan ke atas:

Salin kod Kod adalah seperti berikut:

#include
#include

menggunakan ruang nama v8;

kosongkan SleepFunc(const v8::FunctionCallbackInfo& args) {
Asingkan* asingkan = Asingkan::GetCurrent();
Skop HandleScope(asingkan);
double arg0 = args[0] -> NumberValue();
Tidur(arg0);
}

batal Init(Mengendalikan eksport) {
Asingkan* asingkan = Asingkan::GetCurrent();
eksport->Set(String::NewFromUtf8(isolate, "sleep"),
FunctionTemplate::New(isolate, SleepFunc)->GetFunction());
}

MODUL_NODE(hello, Init);

nod 0.10 dan ke bawah:

Salin kod Kod adalah seperti berikut:

#include
#include

menggunakan ruang nama v8;

Kendalikan SleepFun(Const Arguments& args) {
Skop HandleScope; double arg0 = args[0] -> NumberValue();
Tidur(arg0);
Kembalikan skop.Close(Undefined());
}

batal Init(Mengendalikan eksport) {

eksport->Set(String::NewSymbol("sleep"),
FunctionTemplate::New(SleepFun)->GetFunction());
}

MODUL_NODE(hello, Init);


Ia boleh dilihat bahawa perubahan masih agak besar Alangkah baiknya jika perbezaan ini dapat dilindungi. Saya menulis begitu banyak hanya untuk memberitahu anda bahawa ada jalannya. Sudah tiba masanya untuk meminta perpustakaan nan.

nan

Ingat bahawa dalam binding.gyp, kami memperkenalkan laluan perpustakaan nan, yang akan digunakan di sini. Untuk apa perpustakaan nan? Ia menyediakan lapisan abstraksi yang melindungi perbezaan sintaks antara nodejs 0.8, nodejs 0.10, nodejs 0.12 dan addon sebelum io.js. pujian!

Pasang dahulu: npm install --save nan dan lihat bagaimana fungsi yang sama dilaksanakan selepas menggunakan nan:


Salin kod Kod adalah seperti berikut:
#include
menggunakan ruang nama v8;
KAEDAH_NAN(Tidur){

NanScope();
Double arg0=args[0]->NumberValue();
Tidur(arg0);
NanReturnUndefined();
}

batal Init(Kendalikan eksport){

eksport->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}

MODUL_NODE(hello, Init);


Apa yang anda perlu tahu ialah set nan Bagi set v8, anda tidak perlu memberi perhatian kepadanya.

Melihat dari bawah ke atas:


Salin kod Kod adalah seperti berikut:
NODE_MODULE(hello, Init);

Ayat ini mentakrifkan pintu masuk addon. Ambil perhatian bahawa parameter pertama mestilah konsisten dengan nama_target kami dalam binding.gyp. Parameter kedua ialah fungsi kemasukan addon.

Salin kod Kod adalah seperti berikut:

void Init(Mengendalikan eksport){
eksport->Set(NanSymbol("sleep"), FunctionTemplate::New(Sleep)->GetFunction());
}

Kod ini ialah kaedah kemasukan addon. Ia menerima dua parameter, iaitu eksport dan modul. Contoh di atas meninggalkan parameter kedua. Jika modul menyediakan objek, anda boleh menentukan secara langsung nilai kunci yang akan diberikan kepada eksport seperti yang terdapat dalam contoh jika ia istimewa dan hanya menyediakan nilai atau fungsi, anda perlu menggunakan parameter kedua, serupa dengan NODE_SET_METHOD(modul , "eksport", foo . Dalam contoh ini, ini bermaksud untuk mengeluarkan modul sedemikian:

Salin kod Kod adalah seperti berikut:

{
"tidur": Tidur
}

Tidur ialah fungsi. Mari kita lihat definisi Tidur:

Salin kod Kod adalah seperti berikut:

NAN_METHOD(Tidur){
NanScope();
Double arg0=args[0]->NumberValue();
Tidur(arg0);
NanReturnUndefined();
}

Malah, ia adalah untuk membaca parameter yang diluluskan oleh javascript, menukarnya kepada jenis berganda, dan kemudian memanggil kaedah tidur c.

Kompilasi addon

Sekarang kita akan mula menyusun modul ini. Mula-mula laksanakan konfigurasi nod-gyp untuk menyediakan binaan Ia akan menjana folder binaan dan beberapa fail. Seterusnya jalankan binaan nod-gyp untuk memulakan penyusunan. Dalam contoh ini, fail hello.node akhirnya akan dijana dalam direktori /build/Release/, iaitu modul addon yang akhirnya boleh dirujuk oleh javascript.

Jika terdapat pengubahsuaian seterusnya pada kod c, tidak perlu menjalankan konfigurasi node-gyp, cuma jalankan binaan node-gyp secara langsung.

penggunaan nodej

Buat index.js dan lihat cara menggunakan modul ini:

Salin kod Kod adalah seperti berikut:

var sleep=require('./build/Release/hello.node').sleep;

console.log(Tarikh baharu);
tidur(1000);
console.log(Tarikh baharu);

// keputusan
// Rab 04 Mac 2015 14:55:18 GMT 0800 (Waktu Standard China)
// Rab 04 Mac 2015 14:55:19 GMT 0800 (Waktu Piawai China)  

Es ist ganz einfach, es ist genau das Gleiche wie die Verwendung gewöhnlicher Javascript-Funktionen.

An dieser Stelle wurden die technischen Punkte erläutert, die ich in diesem Artikel teilen möchte. Aber ... wie unterscheidet es sich von der am Anfang bereitgestellten Methode? Ich werde keine Screenshots machen, sondern nur die Ergebnisse direkt erklären:

Da die Add-on-Methode Thread-Suspension verwendet, kommt es theoretisch zu keiner CPU-Auslastung und zu keinen Speicheränderungen, und die Ergebnisse bestätigen dies auch. Schauen wir uns die Art und Weise an, wie JavaScript-Schleifen den Ruhezustand simulieren. Da die Schleife immer läuft, ist es verständlich, dass dies keine große Sache ist. Angesichts der CPU-Auslastung scheint dies durchaus akzeptabel zu sein. Ist das wirklich so? Es ist an der Zeit, dass die Wahrheit ans Licht kommt. Die CPU des von mir getesteten Laptops ist Dual-Core und Four-Threaded. In Kombination mit der CPU-Auslastung von 25 % könnte einer der Dual-Core- und Four-Thread-Threads durch diesen Ruhezustand belegt sein. Tatsächlich habe ich festgestellt, dass in diesem Zeitraum kein einziger Thread gesperrt war, aber das ist nicht das Ergebnis von JavaScript, sondern das Verdienst von Intel Hyper-Threading. Da es sich um vier Threads handelt, besteht das Wesentliche darin, dass die beiden Verarbeitungskerne nur Dual-Threads sein können, die CPU jedoch einen kleinen Trick beim Zeitscheibenschneiden ausführt. Beispielsweise wird der Kern cpu01 in t0 und t2 unterteilt. Angenommen, in einem Tick nach n Ticks (Planungszyklus) wird die Aufgabe t0 und im nächsten Tick t2 zugewiesen. Aus einer relativ langen Zeitskala (relativ zum Planungszeitraum) ist daher die Zeit, in der eine Aufgabe bei t0 und t2 ausgeführt wird, grundsätzlich gleich. Die dargestellte Situation ist also, dass der NodeJS-Prozess t0 oder t2 nicht zu 100 %, sondern jeweils etwa 50 % belegt. Da die Prozessplanung von Windows relativ komplex ist, schwankt die CPU-Auslastung stark. Es kann vorhergesagt werden, dass bei Verwendung einer Dual-Core- und Dual-Thread-CPU zur Verarbeitung dieses Skripts die CPU-Auslastung auf 50 % ansteigt und ein Kern hängen bleibt. Wenn es von einer Single-Core-CPU verarbeitet wird, steigt die CPU plötzlich auf 100 %.

Es scheint, dass der CPU-Bereich etwas zu viel sagt, und der Hyper-Threading-Bereich ist nur Spekulation.

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn