Worker threadlar
Ishchi iplari nima?
Worker Threads Node.js’da joriy etilgan imkoniyat bo‘lib (dastlab v10.5.0 da eksperimental imkoniyat sifatida paydo bo‘lgan va v12 da barqaror holga kelgan), JavaScript kodini bir nechta CPU yadrosida parallel ishga tushirish imkonini beradi.
Alohida Node.js jarayonlarini yaratuvchi child_process yoki cluster modullaridan farqli o‘laroq, Worker Threads xotirani almashishi va haqiqiy parallel JavaScript kodini ishga tushirishi mumkin.
Node.js Worker Threads moduli markaziy protsessor talab qiladigan vazifalar uchun Node.js ning yagona tarmoqli tabiati cheklovlarini ko‘rib chiqadi.
Node.js asinxron hodisalar sikli tufayli kirish/chiqarish bilan bog‘langan operatsiyalarda ustun bo‘lsa-da, u asosiy oqimni blokirovka qilishi va dastur ishlashiga ta’sir qilishi mumkin bo‘lgan CPU bilan bog‘langan vazifalar bilan kurashishi mumkin.
Eslatma: Ishchi mavzular o‘xshash tushunchalarga ega bo‘lsa-da, brauzerlardagi Web ishchilaridan farq qiladi. Node.js ishchi mavzulari Node.js ish vaqti muhiti uchun maxsus ishlab chiqilgan.
Ishchi iplardan qachon foydalanish kerak
Ishchi iplar quyidagilar uchun eng foydalidir:
- CPU-intensive operations (large calculations, data processing)
- Ma’lumotlarni parallel qayta ishlash
- Aks holda asosiy oqimni bloklaydigan operatsiyalar
Ular quyidagilar uchun kerak emas:
- I/O-bound operations (file system, network)
- Allaqachon asinxron API ishlatadigan operatsiyalar
- Tez bajariladigan oddiy vazifalar
Worker Threads modulini import qilish
Worker Threads moduli sukut bo‘yicha Node.js tarkibiga kiritilgan. Siz uni skriptingizda talab qilish orqali foydalanishingiz mumkin:
const {
Worker,
isMainThread,
parentPort,
workerData
} = require('worker_threads');
Asosiy komponentlar
| Komponent | Tavsif |
|---|---|
| Ishchi | Yangi ishchi mavzularni yaratish uchun class |
isMainThread |
Agar kod asosiy oqimda ishlayotgan bo‘lsa, mantiqiy qiymat to‘g‘ri, agar u ishchida ishlayotgan bo‘lsa, noto‘g‘ri |
parentPort |
Agar bu oqim ishchi bo‘lsa, bu asosiy oqim bilan bog‘lanish imkonini beruvchi MessagePort |
workerData |
Ishchi ipni yaratishda ma’lumotlar uzatildi |
MessageChannel |
Aloqa kanalini yaratadi (o‘zaro bog‘langan MessagePort obyektlari juftligi) |
MessagePort |
Mavzular orasidagi xabarlarni yuborish uchun interfeys |
threadId |
Joriy mavzu uchun noyob identifikator |
Birinchi ishchi mavzuingizni yaratish
Keling, oddiy misol yarataylik: unda asosiy oqim (main thread) protsessorni ko‘p talab qiladigan vazifani bajarish uchun worker yaratadi:
// main.js
const { Worker } = require('worker_threads');
// Function to create a new worker
function runWorker(workerData) {
return new Promise((resolve, reject) => {
// Create a new worker
const worker = new Worker('./worker.js', { workerData });
// Listen for messages from the worker
worker.on('message', resolve);
// Listen for errors
worker.on('error', reject);
// Listen for worker exit
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
// Run the worker
async function run() {
try {
// Send data to the worker and get the result
const result = await runWorker('Hello from main thread!');
console.log('Worker result:', result);
} catch (err) {
console.error('Worker error:', err);
}
}
run().catch(err => console.error(err));
// worker.js
const { parentPort, workerData } = require('worker_threads');
// Receive message from the main thread
console.log('Worker received:', workerData);
// Simulate CPU-intensive task
function performCPUIntensiveTask() {
// Simple example: Sum up to a large number
let result = 0;
for (let i = 0; i < 1_000_000; i++) {
result += i;
}
return result;
}
// Perform the task
const result = performCPUIntensiveTask();
// Send the result back to the main thread
parentPort.postMessage({
receivedData: workerData,
calculatedSum: result
});
Ushbu misolda:
- Asosiy oqim ba’zi dastlabki ma’lumotlar bilan worker yaratadi
- Ishchi CPU intensiv hisoblashni amalga oshiradi
- Ishchi natijani asosiy oqimga qaytaradi
- Asosiy oqim natijani oladi va qayta ishlaydi
Misoldagi asosiy tushunchalar
Workerkonstruktori ishchi skript va variantlar obyektiga yo‘l oladiworkerDataopsiyasi ishchiga dastlabki ma’lumotlarni uzatish uchun ishlatiladi- Ishchi
parentPort.postMessage()yordamida asosiy oqimga qaytadi. - Worker hayotiy siklini boshqarish uchun hodisa ishlovchilari (
message,error,exit) ishlatiladi
Mavzular orasidagi aloqa
Ishchi iplar xabarlarni uzatish orqali muloqot qiladi.
Muloqot ikki tomonlama, ya’ni asosiy tarmoq ham, ishchilar ham xabarlarni yuborishi va qabul qilishi mumkin.
Ishchi uchun asosiy oqim
// main.js
const { Worker } = require('worker_threads');
// Create a worker
const worker = new Worker('./message_worker.js');
// Send messages to the worker
worker.postMessage('Hello worker!');
worker.postMessage({ type: 'task', data: [1, 2, 3, 4, 5] });
// Receive messages from the worker
worker.on('message', (message) => {
console.log('Main thread received:', message);
});
// Handle worker completion
worker.on('exit', (code) => {
console.log(`Worker exited with code ${code}`);
});
// message_worker.js
const { parentPort } = require('worker_threads');
// Receive messages from the main thread
parentPort.on('message', (message) => {
console.log('Worker received:', message);
// Process different message types
if (typeof message === 'object' && message.type === 'task') {
const result = processTask(message.data);
parentPort.postMessage({ type: 'result', data: result });
} else {
// Echo the message back
parentPort.postMessage(`Worker echoing: ${message}`);
}
});
// Example task processor
function processTask(data) {
if (Array.isArray(data)) {
return data.map(x => x * 2);
}
return null;
}
Eslatma: Mavzular o‘rtasida uzatilgan xabarlar qiymat bo‘yicha ko‘chiriladi (seriyalashtiriladi), havola orqali ulashilmaydi.
Bu shuni anglatadiki, obyektni bir ipdan ikkinchisiga yuborganingizda, bir ipdagi obyektga kiritilgan o‘zgartirishlar boshqa ipdagi nusxaga ta’sir qilmaydi.
CPU-intensiv vazifaga misol
Bu yerda protsessor talab qiladigan vazifalar uchun ishchi iplardan foydalanishning afzalliklarini ko‘rsatadigan amaliyroq misol:
// fibonacci.js
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
// Recursive Fibonacci function (deliberately inefficient to simulate CPU load)
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
if (isMainThread) {
// This code runs in the main thread
// Function to run a worker
function runFibonacciWorker(n) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, { workerData: n });
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
// Measure execution time with and without workers
async function run() {
const numbers = [40, 41, 42, 43];
// Using a single thread (blocking)
console.time('Single thread');
for (const n of numbers) {
console.log(`Fibonacci(${n}) = ${fibonacci(n)}`);
}
console.timeEnd('Single thread');
// Using worker threads (parallel)
console.time('Worker threads');
const results = await Promise.all(
numbers.map(n => runFibonacciWorker(n))
);
for (let i = 0; i < numbers.length; i++) {
console.log(`Fibonacci(${numbers[i]}) = ${results[i]}`);
}
console.timeEnd('Worker threads');
}
run().catch(err => console.error(err));
} else {
// This code runs in worker threads
// Calculate Fibonacci number
const result = fibonacci(workerData);
// Send the result back to the main thread
parentPort.postMessage(result);
}
Ushbu misol Fibonachchi raqamlarini bitta torli yondashuv va ishchi iplar bilan ko‘p tarmoqli yondashuv yordamida hisoblaydi.
Ko‘p yadroli protsessorda ishchi iplar versiyasi sezilarli darajada tezroq bo‘lishi kerak, chunki u Fibonachchi raqamlarini parallel ravishda hisoblash uchun bir nechta CPU yadrolaridan foydalanishi mumkin.
Ogohlantirish: Ishchi iplar protsessorga bog‘langan vazifalar uchun unumdorlikni sezilarli darajada oshirishi mumkin bo‘lsa-da, ular yaratish va aloqa uchun qo‘shimcha xarajatlar bilan birga keladi. Juda kichik vazifalar uchun bu qo‘shimcha xarajatlar foydadan ko‘proq bo‘lishi mumkin.
Ishchi mavzulari bilan ma’lumotlarni almashish
Tarmoqlar o‘rtasida ma’lumotlarni almashishning bir necha yo‘li mavjud:
- Nusxalarni o‘tkazish:
postMessage()dan foydalanishda standart xatti-harakatlar - Egalik huquqini o‘tkazish:
postMessage()ningtransferListparametridan foydalanish - Xotirani almashish:
SharedArrayBufferdan foydalanish
ArrayBufferlarni uzatish
ArrayBuffer-ni o‘tkazganingizda, siz ma’lumotlarni nusxalamasdan, buferga egalik huquqini bir ipdan ikkinchisiga o‘tkazasiz. Bu katta hajmdagi ma’lumotlar uchun samaraliroq:
// transfer_main.js
const { Worker } = require('worker_threads');
// Create a large buffer
const buffer = new ArrayBuffer(100 * 1024 * 1024); // 100MB
const view = new Uint8Array(buffer);
// Fill with data
for (let i = 0; i < view.length; i++) {
view[i] = i % 256;
}
console.log('Buffer created in main thread');
console.log('Buffer byteLength before transfer:', buffer.byteLength);
// Create a worker and transfer the buffer
const worker = new Worker('./transfer_worker.js');
worker.on('message', (message) => {
console.log('Message from worker:', message);
// After transfer, the buffer is no longer usable in main thread
console.log('Buffer byteLength after transfer:', buffer.byteLength);
});
// Transfer ownership of the buffer to the worker
worker.postMessage({ buffer }, [buffer]);
// transfer_worker.js
const { parentPort } = require('worker_threads');
parentPort.on('message', ({ buffer }) => {
const view = new Uint8Array(buffer);
// Calculate sum to verify data
let sum = 0;
for (let i = 0; i < view.length; i++) {
sum += view[i];
}
console.log('Buffer received in worker');
console.log('Buffer byteLength in worker:', buffer.byteLength);
console.log('Sum of all values:', sum);
// Send confirmation back
parentPort.postMessage('Buffer processed successfully');
});
Eslatma: ArrayBuffer uzatilgandan so‘ng, asl buffer yaroqsiz holga keladi (uning bayt Uzunligi 0 ga aylanadi).
Qabul qiluvchi ip buferga to‘liq kirish huquqiga ega.
SharedArrayBuffer bilan xotira almashish
Ma’lumotlarni nusxalamasdan yoki uzatmasdan oqimlar o‘rtasida almashish kerak bo‘lgan holatlar uchun SharedArrayBuffer bir nechta oqimdan bir xil xotiraga kirish imkonini beradi.
Ogohlantirish: SharedArrayBuffer Spectre zaifliklari bilan bog‘liq xavfsizlik nuqtai nazaridan ba’zi Node.js versiyalarida o‘chirib qo‘yilishi mumkin. Agar kerak bo‘lsa, uni qanday yoqish haqida batafsil ma’lumot uchun Node.js versiyasi hujjatlarini tekshiring.
// shared_main.js
const { Worker } = require('worker_threads');
// Create a shared buffer
const sharedBuffer = new SharedArrayBuffer(4 * 10); // 10 Int32 values
const sharedArray = new Int32Array(sharedBuffer);
// Initialize the shared array
for (let i = 0; i < sharedArray.length; i++) {
sharedArray[i] = i;
}
console.log('Initial shared array in main thread:', [...sharedArray]);
// Create a worker that will update the shared memory
const worker = new Worker('./shared_worker.js', {
workerData: { sharedBuffer }
});
worker.on('message', (message) => {
console.log('Message from worker:', message);
console.log('Updated shared array in main thread:', [...sharedArray]);
// The changes made in the worker are visible here
// because we're accessing the same memory
});
// shared_worker.js
const { parentPort, workerData } = require('worker_threads');
const { sharedBuffer } = workerData;
// Create a new view on the shared buffer
const sharedArray = new Int32Array(sharedBuffer);
console.log('Initial shared array in worker:', [...sharedArray]);
// Modify the shared memory
for (let i = 0; i < sharedArray.length; i++) {
// Double each value
sharedArray[i] = sharedArray[i] * 2;
}
console.log('Updated shared array in worker:', [...sharedArray]);
// Notify the main thread
parentPort.postMessage('Shared memory updated');
Atomika bilan kirishni sinxronlash
Bir nechta mavzular umumiy xotiraga kirganda, poyga sharoitlarini oldini olish uchun kirishni sinxronlashtirish usuli kerak.
Atomics obyekti umumiy xotira massivlarida atom operatsiyalari uchun usullarni taqdim etadi.
// atomics_main.js
const { Worker } = require('worker_threads');
// Create a shared buffer with control flags and data
const sharedBuffer = new SharedArrayBuffer(4 * 10);
const sharedArray = new Int32Array(sharedBuffer);
// Initialize values
sharedArray[0] = 0; // Control flag: 0 = main thread's turn, 1 = worker's turn
sharedArray[1] = 0; // Data value to increment
// Create workers
const workerCount = 4;
const workerIterations = 10;
const workers = [];
console.log(`Creating ${workerCount} workers with ${workerIterations} iterations each`);
for (let i = 0; i < workerCount; i++) {
const worker = new Worker('./atomics_worker.js', {
workerData: { sharedBuffer, id: i, iterations: workerIterations }
});
workers.push(worker);
worker.on('exit', () => {
console.log(`Worker ${i} exited`);
// If all workers have exited, show final value
if (workers.every(w => w.threadId === -1)) {
console.log(`Final value: ${sharedArray[1]}`);
console.log(`Expected value: ${workerCount * workerIterations}`);
}
});
}
// Signal to the first worker to start
Atomics.store(sharedArray, 0, 1);
Atomics.notify(sharedArray, 0);
// atomics_worker.js
const { parentPort, workerData } = require('worker_threads');
const { sharedBuffer, id, iterations } = workerData;
// Create a typed array from the shared memory
const sharedArray = new Int32Array(sharedBuffer);
for (let i = 0; i < iterations; i++) {
// Wait for this worker's turn
while (Atomics.load(sharedArray, 0) !== id + 1) {
// Wait for notification
Atomics.wait(sharedArray, 0, Atomics.load(sharedArray, 0));
}
// Increment the shared counter
const currentValue = Atomics.add(sharedArray, 1, 1);
console.log(`Worker ${id} incremented counter to ${currentValue + 1}`);
// Signal to the next worker
const nextWorkerId = (id + 1) % (iterations === 0 ? 1 : iterations);
Atomics.store(sharedArray, 0, nextWorkerId + 1);
Atomics.notify(sharedArray, 0);
}
// Exit the worker
parentPort.close();
Eslatma: Atomics obyekti umumiy xotiraga kirishni sinxronlashtirish va iplar orasidagi muvofiqlashtirish naqshlarini amalga oshirish uchun load , store , add , wait va notify kabi usullarni taqdim etadi.
Ishchilar pulini yaratish
Aksariyat ilovalar uchun bir vaqtning o‘zida bir nechta vazifalarni bajarish uchun ishchilar pulini yaratishni xohlaysiz.
Mana oddiy ishchi pulining amalga oshirilishi:
// worker_pool.js
const { Worker } = require('worker_threads');
const os = require('os');
const path = require('path');
class WorkerPool {
constructor(workerScript, numWorkers = os.cpus().length) {
this.workerScript = workerScript;
this.numWorkers = numWorkers;
this.workers = [];
this.freeWorkers = [];
this.tasks = [];
// Initialize workers
this._initialize();
}
_initialize() {
// Create all workers
for (let i = 0; i < this.numWorkers; i++) {
this._createWorker();
}
}
_createWorker() {
const worker = new Worker(this.workerScript);
worker.on('message', (result) => {
// Get the current task
const { resolve } = this.tasks.shift();
// Resolve the task with the result
resolve(result);
// Add this worker back to the free workers pool
this.freeWorkers.push(worker);
// Process the next task if any
this._processQueue();
});
worker.on('error', (err) => {
// If a worker errors, terminate it and create a new one
console.error(`Worker error: ${err}`);
this._removeWorker(worker);
this._createWorker();
// Process the next task
if (this.tasks.length > 0) {
const { reject } = this.tasks.shift();
reject(err);
this._processQueue();
}
});
worker.on('exit', (code) => {
if (code !== 0) {
console.error(`Worker exited with code ${code}`);
this._removeWorker(worker);
this._createWorker();
}
});
// Add to free workers
this.workers.push(worker);
this.freeWorkers.push(worker);
}
_removeWorker(worker) {
// Remove from the workers arrays
this.workers = this.workers.filter(w => w !== worker);
this.freeWorkers = this.freeWorkers.filter(w => w !== worker);
}
_processQueue() {
// If there are tasks and free workers, process the next task
if (this.tasks.length > 0 && this.freeWorkers.length > 0) {
const { taskData } = this.tasks[0];
const worker = this.freeWorkers.pop();
worker.postMessage(taskData);
}
}
// Run a task on a worker
runTask(taskData) {
return new Promise((resolve, reject) => {
const task = { taskData, resolve, reject };
this.tasks.push(task);
this._processQueue();
});
}
// Close all workers when done
close() {
for (const worker of this.workers) {
worker.terminate();
}
}
}
module.exports = WorkerPool;
Ishchilar pulidan foydalanish:
// pool_usage.js
const WorkerPool = require('./worker_pool');
const path = require('path');
// Create a worker pool with the worker script
const pool = new WorkerPool(path.resolve(__dirname, 'pool_worker.js'));
// Function to run tasks on the pool
async function runTasks() {
const tasks = [
{ type: 'fibonacci', data: 40 },
{ type: 'factorial', data: 15 },
{ type: 'prime', data: 10000000 },
{ type: 'fibonacci', data: 41 },
{ type: 'factorial', data: 16 },
{ type: 'prime', data: 20000000 },
{ type: 'fibonacci', data: 42 },
{ type: 'factorial', data: 17 },
];
console.time('All tasks');
try {
// Run all tasks in parallel
const results = await Promise.all(
tasks.map(task => {
console.time(`Task: ${task.type}(${task.data})`);
return pool.runTask(task)
.then(result => {
console.timeEnd(`Task: ${task.type}(${task.data})`);
return result;
});
})
);
// Log results
for (let i = 0; i < tasks.length; i++) {
console.log(`${tasks[i].type}(${tasks[i].data}) = ${results[i].result}`);
}
} catch (err) {
console.error('Error running tasks:', err);
} finally {
console.timeEnd('All tasks');
pool.close();
}
}
runTasks().catch(console.error);
// pool_worker.js
const { parentPort } = require('worker_threads');
// Fibonacci function
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// Factorial function
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// Prime count function
function countPrimes(max) {
const sieve = new Uint8Array(max);
let count = 0;
for (let i = 2; i < max; i++) {
if (!sieve[i]) {
count++;
for (let j = i * 2; j < max; j += i) {
sieve[j] = 1;
}
}
}
return count;
}
// Handle messages from the main thread
parentPort.on('message', (task) => {
const { type, data } = task;
let result;
// Perform different calculations based on task type
switch (type) {
case 'fibonacci':
result = fibonacci(data);
break;
case 'factorial':
result = factorial(data);
break;
case 'prime':
result = countPrimes(data);
break;
default:
throw new Error(`Unknown task type: ${type}`);
}
// Send the result back
parentPort.postMessage({ result });
});
Eslatma: Ushbu ishchilar hovuzini amalga oshirish vazifalarni rejalashtirish, ishchi xatolari va ishchilarni avtomatik almashtirish bilan shug‘ullanadi.
Bu haqiqiy dunyo ilovalari uchun yaxshi boshlanish nuqtasidir, lekin uni ishchi vaqtlari va ustuvor vazifalar kabi xususiyatlar bilan kengaytirish mumkin.
Amaliy qo‘llanilishi: Rasmga ishlov berish
Tasvirni qayta ishlash ishchi iplar uchun mukammal foydalanish holatidir, chunki u ham protsessor talab qiladi, ham oson parallelizatsiya qilinadi.
Mana parallel tasvirni qayta ishlashga misol:
// image_main.js
const { Worker } = require('worker_threads');
const path = require('path');
const fs = require('fs');
// Function to process an image in a worker
function processImageInWorker(imagePath, options) {
return new Promise((resolve, reject) => {
const worker = new Worker('./image_worker.js', {
workerData: {
imagePath,
options
}
});
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
// Main function to process multiple images in parallel
async function processImages() {
const images = [
{ path: 'image1.jpg', options: { grayscale: true } },
{ path: 'image2.jpg', options: { blur: 5 } },
{ path: 'image3.jpg', options: { sharpen: 10 } },
{ path: 'image4.jpg', options: { resize: { width: 800, height: 600 } } }
];
console.time('Image processing');
try {
// Process all images in parallel
const results = await Promise.all(
images.map(img => processImageInWorker(img.path, img.options))
);
console.log('All images processed successfully');
console.log('Results:', results);
} catch (err) {
console.error('Error processing images:', err);
}
console.timeEnd('Image processing');
}
// Note: This is a conceptual example.
// In a real application, you would use an image processing library like sharp or jimp
// and provide actual image files.
// processImages().catch(console.error);
console.log('Image processing example (not actually running)');
// image_worker.js
const { parentPort, workerData } = require('worker_threads');
const { imagePath, options } = workerData;
// In a real application, you would import an image processing library here
// const sharp = require('sharp');
// Simulate image processing
function processImage(imagePath, options) {
console.log(`Processing image: ${imagePath} with options:`, options);
// Simulate processing time based on options
let processingTime = 500; // Base time in ms
if (options.grayscale) processingTime += 200;
if (options.blur) processingTime += options.blur * 50;
if (options.sharpen) processingTime += options.sharpen * 30;
if (options.resize) processingTime += 300;
// Simulate the actual processing
return new Promise(resolve => {
setTimeout(() => {
// Return simulated result
resolve({
imagePath,
outputPath: `processed_${imagePath}`,
processing: options,
dimensions: options.resize || { width: 1024, height: 768 },
size: Math.floor(Math.random() * 1000000) + 500000 // Random file size
});
}, processingTime);
});
}
// Process the image and send the result back
processImage(imagePath, options)
.then(result => {
parentPort.postMessage(result);
})
.catch(err => {
throw err;
});
Worker Threads, Child Process va Cluster: taqqoslash
Boshqa Node.js parallellik mexanizmlariga nisbatan Worker Threads dan qachon foydalanishni tushunish muhim:
| Xususiyat | Ishchi iplari | Bolalar jarayoni | klaster |
|---|---|---|---|
| Umumiy xotira | Yes (via SharedArrayBuffer) | Yo‘q (faqat IPC) | Yo‘q (faqat IPC) |
| Resurslardan foydalanish | Lower (shared V8 instance) | Higher (separate processes) | Higher (separate processes) |
| Ishga tushirish vaqti | Tezroq | Sekinroq | Sekinroq |
| Izolyatsiya | Lower (shares event loop) | Higher (full process isolation) | Higher (full process isolation) |
| Muvaffaqiyatsizlik ta’siri | Ota oqimga (parent thread) ta’sir qilishi mumkin | Bolalar jarayoni bilan cheklangan | Worker jarayoni bilan cheklangan |
| Eng yaxshisi | CPU talab qiladigan vazifalar | Running different programs | Ilovalarni masshtablash |
Ishchi iplardan qachon foydalanish kerak
- Raqamlarni kesish, tasvirni qayta ishlash yoki siqish kabi CPU bilan bog‘liq vazifalar
- Yaxshi ishlash uchun umumiy xotira kerak bo‘lganda
- Bitta Node.js misolida parallel JavaScript kodini ishga tushirishingiz kerak bo‘lganda
Child Process qachon ishlatiladi
- Tashqi dasturlar yoki buyruqlarni ishga tushirish
- Boshqa tillardagi vazifalarni bajarish
- Asosiy jarayon va tug‘ilgan jarayonlar o‘rtasida kuchliroq izolyatsiya kerak bo‘lganda
Klasterdan qachon foydalanish kerak
- HTTP serverni bir nechta yadro bo‘ylab masshtablash
- Load balancing incoming connections
- Ilovaning barqarorligi va uzluksiz ishlash vaqtini (uptime) oshirish
Eng yaxshi amaliyotlar
- Tizimlardan ortiqcha foydalanmang: Faqat asosiy oqimni bloklaydigan protsessor talab qiladigan vazifalar uchun ishchi iplardan foydalaning.
- Ustki xarajatlarni ko‘rib chiqing: Mavzular yaratishda yuqori xarajatlar mavjud. Juda qisqa vazifalar uchun bu qo‘shimcha xarajatlar foydadan ko‘proq bo‘lishi mumkin.
- Ishchilar pulidan foydalaning: Har bir vazifa uchun ularni yaratish va yo‘q qilish o‘rniga bir nechta vazifalar uchun ishchilarni qayta ishlating.
- Ma’lumot uzatishni minimallashtiring: Egalikni ArrayBuffer bilan o‘tkazing yoki katta hajmdagi ma’lumotlar bilan ishlashda SharedArrayBuffer-dan foydalaning.
- Xatolarni to‘g‘ri hal qiling: Har doim ishchilarning xatolarini ushlang va ishchi xatolari uchun strategiyaga ega bo‘ling.
- Ishchining hayotiy davrlarini kuzatib boring: Xodimlarning sog‘lig‘ini kuzatib boring va agar ular halokatga uchrasa, ularni qayta ishga tushiring.
- Tegishli sinxronizatsiyadan foydalaning: Umumiy xotiraga kirishni muvofiqlashtirish uchun Atomics-dan foydalaning.
- Yechimingizni solishtiring: Ish zarralari haqiqatda yordam berishiga ishonch hosil qilish uchun har doim ishlash yaxshilanishini o‘lchang.
Ogohlantirish: Threading kodingizga murakkablik kiritadi. Ishchi iplardan faqat parallel bajarish uchun chinakam ehtiyoj mavjud bo‘lganda foydalaning. Kirish/chiqish bilan bog‘langan operatsiyalar uchun Node.js-ning o‘rnatilgan asinxron API’lari odatda samaraliroq bo‘ladi.
Xulosa
Worker Threads moduli Node.js-da haqiqiy multithreading imkoniyatlarini taqdim etadi, bu esa markaziy protsessor talab qiladigan vazifalarni asosiy voqea siklini bloklamasdan parallel ravishda bajarishga imkon beradi.
Ushbu qo‘llanmada biz quyidagilarni ko‘rib chiqdik:
SharedArrayBufferyordamida mavzular o‘rtasida ma’lumotlarni almashish- Mavzuga kirishni
Atomicsbilan sinxronlash - Vazifalarni samarali boshqarish uchun qayta ishlatiladigan ishchilar pulini yaratish
- Parallel tasvirni qayta ishlash kabi amaliy ilovalar
- Boshqa Node.js parallellik modellari bilan taqqoslash
- Ishchi iplardan samarali foydalanish bo‘yicha eng yaxshi amaliyotlar
W3Schools Pathfinder
Yutuqlaringizni kuzating – bu bepul!
