paint-brush
নোডজেএস: আপনি কলব্যাকে ফিরে গেলে 4.8x দ্রুত!দ্বারা@gemmablack
20,095 পড়া
20,095 পড়া

নোডজেএস: আপনি কলব্যাকে ফিরে গেলে 4.8x দ্রুত!

দ্বারা Gemma Black9m2024/02/12
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

কলব্যাক 4.8x দ্রুততর হয় যখন সেগুলিকে সমান্তরালভাবে অ্যাসিঙ্ক/অপেক্ষায় সমান্তরালভাবে চালানো হয়। এবং শুধুমাত্র 1.9x দ্রুততর যখন আমরা ক্রমিক কলব্যাক চালাই।
featured image - নোডজেএস: আপনি কলব্যাকে ফিরে গেলে 4.8x দ্রুত!
Gemma Black HackerNoon profile picture

হ্যাঁ, বলেছি!


কলব্যাক 4.8x দ্রুততর হয় যখন সেগুলিকে সমান্তরালভাবে async/await এর উপর সমান্তরালভাবে চালানো হয়। এবং মাত্র 1.9x দ্রুত যখন আমরা ক্রমিক কলব্যাক চালাই।


আমার ডজি পরীক্ষা সম্পর্কে কিছু সহায়ক এবং সদয় মন্তব্য পাওয়ার পরে আমি এই নিবন্ধটি কিছুটা সংশোধন করেছি। 😂🙏


আপনাকে ধন্যবাদ রিকার্ডো লোপেস এবং রায়ান পো বেঞ্চমার্কগুলিকে সঠিক দিকে নিয়ে যাওয়ার জন্য সময় নেওয়ার জন্য। আমার প্রথম ভুলটি হল আমি আসলে কোডটি কার্যকর করার জন্য শেষ করার জন্য অপেক্ষা করছিলাম না, যা ফলাফলগুলিকে পাগলামি করে। দ্বিতীয়টি ছিল আমি অনুক্রমিক রানটাইমের সমান্তরাল তুলনা করছিলাম, যা বেঞ্চমার্কগুলিকে মূল্যহীন করে তোলে।


তাই এই বৃত্তাকার 2 যা আমার প্রাথমিক ত্রুটির ঠিকানা. আগে, আমি বলেছিলাম:


মূলত, আমি লিখেছিলাম, যে NodeJS 34.7x দ্রুত হবে যদি আমরা কলব্যাকে ফিরে যাই! 🤣 ভুল।


আগে আমার খারাপ বেঞ্চমার্কের মতো চিত্তাকর্ষক নয় (এবং প্রসঙ্গের জন্য মন্তব্যগুলি দেখুন), তবে এখনও একটি বড় পার্থক্য।

তাই আমি ঠিক কি পরীক্ষা করেছি?

আমি 10,000 বার একটি ফাইল পড়ার সময় প্রতিশ্রুতি এবং অ্যাসিঙ্ক/অপেক্ষার সাথে কলব্যাকের তুলনা করেছি। এবং সম্ভবত এটি একটি নির্বোধ পরীক্ষা কিন্তু আমি জানতে চেয়েছিলাম, যা I/O এ দ্রুততর।


তারপরে আমি অবশেষে Go এর সাথে Node.js-এ কলব্যাকের তুলনা করি!


এখন ভাবুন, কে জিতেছে?


আমি খারাপ হবে না. TLDR । গোলং !


স্বল্পতা ভালো. ফলাফল ms .


এখন, সত্যিকারের বেঞ্চমার্কার? এই এক আমার উপর সহজ যান. তবে আমাকে একজন ভালো মানুষ হিসেবে গড়ে তুলতে আপনার মন্তব্য করুন।

সবাই বলছে যে Node.js ধীর!

এবং এটা আমাকে বাগ আউট.


কারণ ধীর মানে কি? সমস্ত বেঞ্চমার্কের মতো, আমারটি প্রাসঙ্গিক।


আমি সম্পর্কে পড়া শুরু ইভেন্ট লুপ , শুধু এমনকি বুঝতে শুরু কিভাবে এটা কাজ করে .


কিন্তু প্রধান জিনিসটি আমি বুঝতে পেরেছি যে Node.js I/O কাজগুলিকে একটি সারিতে পাস করে যা প্রধান Node.js এক্সিকিউটেবল থ্রেডের বাইরে বসে থাকে। এই সারি চলছে বিশুদ্ধ সি . বেশ কয়েকটি থ্রেড সম্ভাব্যভাবে এই I/O অপারেশনগুলি পরিচালনা করতে পারে। এবং সেখানেই Node.js জ্বলজ্বল করতে পারে, I/O পরিচালনা করে।


প্রতিশ্রুতি, যাইহোক, প্রধান, একক এক্সিকিউটেবল থ্রেডে পরিচালনা করা হয়। এবং অ্যাসিঙ্ক/অপেক্ষা, ভাল, প্রতিশ্রুতি কিন্তু এখন ব্লক করা যোগ করা হয়েছে।

ইভেন্ট লুপ 6টি ভিন্ন সারি নিয়ে গঠিত। থেকে: https://www.builder.io/blog/visual-guide-to-nodejs-event-loop

তাহলে প্রতিশ্রুতির চেয়ে কলব্যাক কি দ্রুত?

এর পরীক্ষা করা যাক.


প্রথম বন্ধ. আমার মেশিন ! সাথে কাজ করার পরিপূরক কাম্মা . আমরা কোন সংস্থানগুলির সাথে কাজ করছি তা নোট করা গুরুত্বপূর্ণ৷ প্রচুর মেমরি এবং সিপিইউ।

 MacBook Pro (14-inch, 2021) Chip Apple M1 Pro Memory 32 GB Cores 10 NodeJS v20.8.1

তাই আমাদের কাছে একটি মূল বার্তা সহ একটি text.txt ফাইল আছে, Hello, world

 echo "Hello, world" > text.txt

এবং আমরা নেটিভ Node.js ব্যবহার করে এই টেক্সট ফাইলটি পড়ব, যার মানে, শূন্য নোড মডিউল নির্ভরতা কারণ আমরা মহাবিশ্বের সবচেয়ে ভারী বস্তুর সাথে গতিকে টেনে আনতে চাই না।

কলব্যাক

সমান্তরাল কলব্যাক

প্রথমে, সমান্তরাল কলব্যাক দিয়ে শুরু করা যাক। আমি আগ্রহী যে একই ফাইলটি যত তাড়াতাড়ি সম্ভব, একবারে পড়া যায়। এবং কি সমান্তরাল চেয়ে দ্রুত?

 // > file-callback-parallel.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs"; test('reading file 10,000 times with callback parallel', (t, done) => { let count = 0; for (let i = 0; i < 10000; i++) { fs.readFile("./text.txt", { encoding: 'utf-8'}, (err, data) => { assert.strictEqual(data, "Hello, world"); count++ if (count === 10000) { done() } }) } });

ক্রমিক কলব্যাক

দ্বিতীয়ত, আমাদের আবার কলব্যাক আছে, কিন্তু অনুক্রমিক (বা বরং ব্লকিং)। আমি কত দ্রুত একই ফাইল ক্রমিকভাবে পড়া যেতে পারে আগ্রহী। যুগ যুগ ধরে কলব্যাক কলব্যাক কলব্যাক না করে, এটি আবার চেষ্টা করার মজা ছিল। যদিও, এটা সুন্দর দেখায় না.

 // > file-callback-blocking.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs"; let read = (i, callback) => { fs.readFile("./text.txt", { encoding: 'utf-8'}, (err, data) => { assert.strictEqual(data, "Hello, world"); i += 1 if (i === 10000) { return callback() } read(i, callback) }) } test('reading file 10,000 times with callback blocking', (t, done) => { read(0, done) });

অ্যাসিঙ্ক/অপেক্ষা করুন

তারপর আমরা async/অপেক্ষা করি। Nodejs এর সাথে কাজ করার আমার প্রিয় উপায়।

সমান্তরাল অ্যাসিঙ্ক/অপেক্ষা করুন

আমি async/await এর সাথে পেতে পারি এটি ততটাই সমান্তরাল। আমি সমস্ত readFile অপারেশন একটি অ্যারেতে লোড করি এবং Promise.all ব্যবহার করে সেগুলির জন্য অপেক্ষা করি।

 // > file-async-parallel.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs/promises"; test('reading file 10,000 times with async parallel', async (t) => { let allFiles = [] for (let i = 0; i < 10000; i++) { allFiles.push(fs.readFile("./text.txt", { encoding: 'utf-8'})) } return await Promise.all(allFiles) .then(allFiles => { return allFiles.forEach((data) => { assert.strictEqual(data, "Hello, world"); }) }) });

অনুক্রমিক অ্যাসিঙ্ক/অপেক্ষা করুন

এটি লিখতে সবচেয়ে সহজ এবং সবচেয়ে সংক্ষিপ্ত ছিল।

 // > file-async-blocking.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs/promises"; test('reading file 10,000 times with async blocking', async (t) => { for (let i = 0; i < 10000; i++) { let data = await fs.readFile("./text.txt", { encoding: 'utf-8'}) assert.strictEqual(data, "Hello, world"); } });

প্রতিশ্রুতি

অবশেষে, আমরা অ্যাসিঙ্ক/অপেক্ষা ছাড়াই প্রতিশ্রুতি দিয়েছি। আমি দীর্ঘকাল ধরে async/await পক্ষে সেগুলি ব্যবহার করা বন্ধ করেছি তবে তারা পারফরম্যান্স ছিল কিনা তা নিয়ে আমি আগ্রহী ছিলাম।

সমান্তরাল প্রতিশ্রুতি

 // > file-promise-parallel.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs/promises"; test('reading file 10,000 times with promise parallel', (t, done) => { let allFiles = [] for (let i = 0; i < 10000; i++) { allFiles.push(fs.readFile("./text.txt", { encoding: 'utf-8'})) } Promise.all(allFiles) .then(allFiles => { for (let i = 0; i < 10000; i++) { assert.strictEqual(allFiles[i], "Hello, world"); } done() }) });

ধারাবাহিক প্রতিশ্রুতি।

আবার, আমরা সমস্ত readFile অপারেশনের জন্য অপেক্ষা করতে চাই।

 // > file-promise-blocking.test.mjs import test from 'node:test'; import assert from 'node:assert'; import fs from "node:fs/promises"; test('reading file 10,000 times with promises blocking', (t, done) => { let count = 0; for (let i = 0; i < 10000; i++) { let data = fs.readFile("./text.txt", { encoding: 'utf-8'}) .then(data => { assert.strictEqual(data, "Hello, world") count++ if (count === 10000) { done() } }) } });

আর ভয়েলা! ফলাফল 🎉! আমি এমনকি একটি ভাল পড়া পেতে এটি কয়েকবার দৌড়ে.

আমি এভাবে প্রতিটি পরীক্ষা চালিয়েছি:

 node --test <file>.mjs

কলব্যাক সহ একটি ফাইল 10,000 বার পড়া সমান্তরালভাবে অ্যাসিঙ্ক/ওয়েট করার চেয়ে 5.8 গুণ বেশি দ্রুত! সমান্তরালভাবে প্রতিশ্রুতির তুলনায় এটি 4.7x দ্রুত!


সুতরাং, Node.js জমিতে, কলব্যাকগুলি আরও কার্যকর!

এখন Go Node.js এর চেয়ে দ্রুত?

ঠিক আছে, আমি গো-তে লিখি না, তাই এটি সত্যিই ভয়ানক কোড হতে পারে কারণ আমি ChatGPT কে আমাকে সাহায্য করতে বলেছিলাম এবং এখনও, এটি বেশ শালীন বলে মনে হচ্ছে


হেই হো. চলো যাই. আমাদের গোলং কোড।

 package main import ( "fmt" "io/ioutil" "time" ) func main() { startTime := time.Now() for i := 0; i < 10000; i++ { data, err := ioutil.ReadFile("./text.txt") if err != nil { fmt.Printf("Error reading file: %v\n", err) return } if string(data) != "Hello, world" { fmt.Println("File content mismatch: got", string(data), ", want Hello, world") return } } duration := time.Since(startTime) fmt.Printf("Test execution time: %v\n", duration) }

এবং আমরা এটি এভাবে চালাই:

 go run main.go

আর ফলাফল?

 Test execution time: 58.877125ms

🤯 Go ক্রমিক কলব্যাক ব্যবহার করে Node.js এর থেকে 4.9x দ্রুত। Node.js শুধুমাত্র সমান্তরাল নির্বাহের সাথে কাছাকাছি আসে।


Node.js Async/await Go থেকে 9.2x ধীর।


তাই হ্যাঁ. Node.js ধীর। এখনও, সাব 300ms এর মধ্যে 10,000 ফাইল নিয়ে উপহাস করা যাবে না। কিন্তু আমি গো এর দ্রুততা দেখে নম্র হয়েছি!

এখন শুধু একটি পার্শ্ব নোট. আমার কি খারাপ বেঞ্চমার্ক আছে?

আমি সত্যিই ভয়ানক মানদণ্ড আছে. রিকার্ডো এবং রায়ানকে আবার ধন্যবাদ।


হ্যা, আমি করেছিলাম. আশা করি এখন তারা ভালো আছেন।


কিন্তু আপনি জিজ্ঞাসা করতে পারেন, কে সত্যিই একই ফাইল পড়তে যাচ্ছে, বারবার? কিন্তু জিনিসগুলির মধ্যে একটি আপেক্ষিক পরীক্ষার জন্য, আমি আশা করি এটি একটি সহায়ক তুলনা।


আমি জানি না কত থ্রেড Node.js ব্যবহার করছে।


আমি জানি না কিভাবে আমার CPU কোরগুলি Go বনাম Node.js পারফরম্যান্সকে প্রভাবিত করে৷


আমি শুধু একটি কোর সহ একটি AWS মেশিন ভাড়া নিতে পারি এবং তুলনা করতে পারি।


এটা কি কারণ আমি ম্যাক এম 1 এ আছি?


লিনাক্স বা...উইন্ডোজে Node.js কিভাবে পারফর্ম করবে? 😱


এবং বাস্তবতা আছে, হ্যাঁ, একটি ফাইল পড়া একটি জিনিস, কিন্তু কিছু সময়ে, ফাইলের ডেটার সাথে কিছু করার জন্য ফাইলটি পড়ার জন্য আপনাকে অপেক্ষা করতে হবে। সুতরাং, মূল থ্রেডে গতি এখনও বেশ গুরুত্বপূর্ণ।

এখন, আপনি কি সত্যিই কলব্যাক ব্যবহার করতে চান?

আমি বলতে চাচ্ছি, আপনি কি সত্যিই চান?


আমি জানি না আমি নিশ্চিতভাবে কাউকে বলতে চাই না কি করতে হবে।

কিন্তু আমি async/awaits এর পরিষ্কার সিনট্যাক্স পছন্দ করি।


তারা আরও ভাল দেখতে.


তারা আরও ভাল পড়ে।


আমি ভাল জানি এখানে বিষয়গত কিন্তু আমার মনে আছে কলব্যাক-হেল, এবং যখন প্রতিশ্রুতি অস্তিত্বে আসে তখন আমি কৃতজ্ঞ ছিলাম। এটি জাভাস্ক্রিপ্ট সহনীয় করে তুলেছে।


এখন, Golang স্পষ্টতই Node.js এর চেয়ে দ্রুততর, কলব্যাক সহ, এবং async/await সহ, 9.2x দ্বারা! সুতরাং আমরা যদি ভাল পঠনযোগ্যতা এবং কর্মক্ষমতা চাই, গোলং বিজয়ী। যদিও, আমি শিখতে চাই যে কীভাবে গোলং হুডের নীচে দেখায়।


যে কোন এই মজা ছিল. ইভেন্ট লুপে কলব্যাক এবং I/O কীভাবে কাজ করে তা বুঝতে সাহায্য করার জন্য এটি একটি অনুশীলন ছিল।

তাই সাইন আউট করতে

Node.js কি ধীর? নাকি আমরা স্লো মোডে Node.js ব্যবহার করছি?


সম্ভবত যেখানে পারফরম্যান্স গুরুত্বপূর্ণ, গোলং লাফের মূল্য। আমি অবশ্যই ভবিষ্যতে গোলং ব্যবহার করার বিষয়ে আরও দেখব।


এছাড়াও এখানে উপস্থিত হয়.