Child Process moduli


ULASHISH

Bolalar jarayoni moduli nima?

Child Process moduli o‘rnatilgan Node.js moduli bo‘lib, u sizga bolalar jarayonlarini yaratish va boshqarish imkonini beradi.

U tashqi buyruqlarni bajarish va subprocess instances bilan aloqa qilishning bir necha usullarini taqdim etadi.

Bu qobiliyat quyidagi vazifalar uchun zarur:

  • Node.js ilovangizdan tizim buyruqlarini ishga tushirish
  • Alohida jarayonlarda protsessor talab qiladigan vazifalarni bajarish
  • Bir nechta protsessor yadrolaridan foydalanish uchun bir nechta jarayonlarni parallel ravishda bajarish
  • Tashqi dasturlar va skriptlar bilan o‘zaro ishlash

Child jarayoni modulini import qilish

Child Process moduli sukut bo‘yicha Node.js tarkibiga kiritilgan.

Siz uni skriptingizda talab qilish orqali foydalanishingiz mumkin:

const childProcess = require('child_process');

// Or using destructuring to access specific methods
const { exec, spawn, fork } = require('child_process');

Bolalar jarayonlarini yaratish usullari

Child Process moduli bolalar jarayonlarini yaratish va boshqarishning to‘rtta asosiy usulini taqdim etadi, ularning har biri turli xatti-harakatlar va foydalanish holatlariga ega:

Metod Tavsif Foydalanish holati
exec() Qobiq hosil qiladi va buyruqni bajaradi, natijani buferlaydi Shell buyrug‘ini ishga tushirish va bir vaqtning o‘zida butun chiqishni olish kerak bo‘lganda
execFile() exec() ga o‘xshaydi, lekin qobiq hosil qilmaydi Qobiq talqinisiz faylga asoslangan buyruqlarni bajarish uchun samaraliroq
spawn() Oqimli I/U bilan qobiq yaratmasdan yangi jarayonni yaratadi Uzoq davom etadigan jarayonlar yoki katta ishlab chiqarish bilan shug‘ullanganda
fork() Node.js jarayonlarini yaratish uchun spawn() ning maxsus holati Boshqa Node.js modulini IPC bilan alohida jarayon sifatida ishga tushirishingiz kerak bo‘lganda


exec() metodi

exec() usuli qobiq hosil qiladi va shu qobiq ichida buyruqni bajaradi.

U butun chiqishni buferlaydi va buyruq tugashi bilan uni callback funksiyasi orqali ta’minlaydi.

const { exec } = require('child_process');

// Execute the 'ls -la' command (or 'dir' on Windows)
const command = process.platform === 'win32' ? 'dir' : 'ls -la';

exec(command, (error, stdout, stderr) => {
  if (error) {
    console.error(`Error executing command: ${error.message}`);
    return;
  }

  if (stderr) {
    console.error(`Command stderr: ${stderr}`);
  }

  console.log(`Command output:\n${stdout}`);
});

// With options
exec('echo $HOME', {
  env: { HOME: '/custom/home/directory' }
}, (error, stdout, stderr) => {
  console.log(`Custom home directory: ${stdout.trim()}`);
});

Ogohlantirish: Hech qachon exec() ga tozalanmagan foydalanuvchi ma’lumotlarini o‘tkazmang, chunki u to‘liq qobiq sintaksisi bilan buyruqlarni bajaradi, bu esa buyruqlar kiritish hujumlariga olib kelishi mumkin.

exec() Promise bilan

callback-ni boshqarish uchun Promise paketidan foydalanish:

const { exec } = require('child_process');
const util = require('util');

// Convert exec to a promise-based function
const execPromise = util.promisify(exec);

async function executeCommand(command) {
  try {
    const { stdout, stderr } = await execPromise(command);

    if (stderr) {
      console.error(`Command stderr: ${stderr}`);
    }

    console.log(`Command output:\n${stdout}`);
    return stdout;
  } catch (error) {
    console.error(`Error executing command: ${error.message}`);
    throw error;
  }
}

// Using the promise-based function
executeCommand('node --version')
  .then(version => console.log(`Node.js version: ${version.trim()}`))
  .catch(err => console.error('Failed to get Node.js version'));

execFile() metodi

execFile() usuli exec() ga o‘xshaydi, lekin u qobiq hosil qilmaydi.

Bu tashqi ikkilik fayllarni bajarish uchun samaraliroq.

const { execFile } = require('child_process');

// Execute 'node' with arguments
execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    console.error(`Error executing file: ${error.message}`);
    return;
  }

  console.log(`Node.js version: ${stdout.trim()}`);
});

// On Windows, execute a batch file
if (process.platform === 'win32') {
  execFile('C:\\Windows\\System32\\cmd.exe', ['/c', 'echo Hello from batch!'], (error, stdout, stderr) => {
    if (error) {
      console.error(`Error: ${error.message}`);
      return;
    }

    console.log(`Output: ${stdout.trim()}`);
  });
}

Eslatma: execFile() exec() ga qaraganda foydalanuvchi kiritishi bilan buyruqlarni bajarish uchun xavfsizroq, chunki u qobiq meta-belgilarini qayta ishlamaydi.


spawn() metodi

spawn() usuli berilgan buyruq bilan yangi jarayonni ishga tushiradi.

exec() dan farqli o‘laroq, u chiqishni buferlamaydi, aksincha, stdout va stderr-ga oqimga asoslangan kirishni ta’minlaydi.

const { spawn } = require('child_process');

// Spawn a process to list files
const ls = process.platform === 'win32'
  ? spawn('cmd', ['/c', 'dir'])
  : spawn('ls', ['-la']);

// Handle process output streams
ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`Child process exited with code ${code}`);
});

// Spawn with options
const grep = spawn('grep', ['hello', 'input.txt'], {
  cwd: '/tmp', // Working directory
  env: { ...process.env, CUSTOM_ENV: 'value' },
  stdio: 'pipe', // Configure stdio
  detached: false, // Process group behavior
  shell: false // Whether to run in a shell
});

// Handling errors
grep.on('error', (err) => {
  console.error(`Failed to start subprocess: ${err.message}`);
});

spawn() qachon ishlatiladi

spawn() ayniqsa quyidagilar uchun foydalidir:

  • Uzoq davom etadigan jarayonlar (masalan, server jarayonlari yoki kuzatuvchilar (watchers))
  • Ko‘p miqdorda mahsulot ishlab chiqaradigan jarayonlar
  • Tugallanishni kutish o‘rniga, ma’lumotlarni yaratilganidek qayta ishlash kerak bo‘lganda

spawn()’ni stdin bilan ishlatish

const { spawn } = require('child_process');

// Spawn a process that reads from stdin
const process = spawn('wc', ['-w']); // Word count

// Send data to the process's stdin
process.stdin.write('Hello world from Node.js!');
process.stdin.end(); // Signal the end of input

// Capture output
process.stdout.on('data', (data) => {
  console.log(`Number of words: ${data}`);
});

fork() metodi

fork() usuli Node.js jarayonlarini yaratish uchun maxsus spawn() ning maxsus holatidir. U ota-ona va bola jarayonlari o‘rtasida xabarlar yuborish imkonini beruvchi IPC kanalini o‘rnatadi.

// In the main file (parent.js)
const { fork } = require('child_process');

// Fork a child process
const child = fork('child.js');

// Send a message to the child
child.send({ message: 'Hello from parent' });

// Receive messages from the child
child.on('message', (message) => {
  console.log('Message from child:', message);
});

// Handle child process exit
child.on('close', (code) => {
  console.log(`Child process exited with code ${code}`);
});
// In the child file (child.js)
console.log('Child process started', process.pid);

// Listen for messages from the parent
process.on('message', (message) => {
  console.log('Message from parent:', message);

  // Send a message back to the parent
  process.send({ response: 'Hello from child' });

  // After 3 seconds, exit the process
  setTimeout(() => {
    process.exit(0);
  }, 8080);
});

fork() afzalliklari

  • Har bir vilkali jarayon o‘zining V8 nusxasini va xotirasini oladi
  • Protsessor talab qiladigan ishni asosiy voqealar siklidan ajratib turadi
  • Xabarlar orqali jarayonlar o‘rtasida aloqa o‘rnatishga imkon beradi
  • Bir nechta CPU yadrolaridan foydalanishga yordam beradi

Jarayonlararo aloqa (IPC)

fork() bilan yaratilgan bolalar jarayonlari send() va message hodisasi yordamida o‘rnatilgan IPC kanali orqali ota-ona jarayoni bilan bog‘lanishi mumkin.

Murakkab ma’lumotlarni yuborish

// In parent.js
const { fork } = require('child_process');
const child = fork('worker.js');

// Send different types of data
child.send({
  command: 'compute',
  data: [1, 2, 3, 4, 5],
  options: {
    multiply: 2,
    subtract: 1
  }
});

// Receive the result
child.on('message', (result) => {
  console.log('Computation result:', result);
  child.disconnect(); // Clean up the IPC channel
});
// In worker.js
process.on('message', (msg) => {
   if (msg.command === 'compute') {
    const result = msg.data.map(num => num * msg.options.multiply - msg.options.subtract);

    // Send the result back to the parent
    process.send({ result });
  }
});

Eslatma: Xabarlar JSON yordamida ketma-ketlashtiriladi, shuning uchun siz faqat JSON-mos keladigan ma’lumotlarni (obyektlar, massivlar, stringlar, raqamlar, mantiqiy va null) yuborishingiz mumkin.


Bolalar jarayonlarini boshqarish

Bolani o‘ldirish jarayoni

const { spawn } = require('child_process');

// Spawn a long-running process
const child = spawn('node', ['-e', `
  setInterval(() => {
    console.log('Still running...', Date.now());
  }, 1000);
`]);

// Output from the process
child.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

// Kill the process after 5 seconds
setTimeout(() => {
  console.log('Killing the child process...');

  // Send a SIGTERM signal
  child.kill('SIGTERM');

  // Alternative: child.kill() - uses SIGTERM by default
}, 5000);

// Handle the exit event
child.on('exit', (code, signal) => {
  console.log(`Child process exited with code ${code} and signal ${signal}`);
});

Ajratilgan jarayonlar

Siz ota-onadan mustaqil ravishda ishlashda davom etadigan alohida bolalar jarayonlarini yaratishingiz mumkin:

const { spawn } = require('child_process');
const fs = require('fs');

// Create a detached process
const child = spawn('node', ['long_running_script.js'], {
  detached: true,
  stdio: ['ignore',
    fs.openSync('output.log', 'w'),
    fs.openSync('error.log', 'w')
  ]
});

// Unref the child to allow the parent to exit independently
child.unref();

console.log(`Started detached process with PID: ${child.pid}`);
console.log('Parent will exit while child continues running.');

// The parent can now exit, and the child will continue running

Amaliy misollar

Oddiy vazifa navbatini yaratish

// In tasks.js (parent)
const { fork } = require('child_process');
const numCPUs = require('os').cpus().length;

class TaskQueue {
  constructor() {
    this.tasks = [];
    this.workers = [];
    this.maxWorkers = numCPUs;
  }

  addTask(task) {
    this.tasks.push(task);
    this.runNext();
  }

  runNext() {
    // If we have tasks and available workers
    if (this.tasks.length > 0 && this.workers.length < this.maxWorkers) {
      const task = this.tasks.shift();
      const worker = fork('worker.js');

      console.log(`Starting worker for task ${task.id}`);
      this.workers.push(worker);

      worker.send(task);

      worker.on('message', (result) => {
        console.log(`Task ${task.id} completed with result:`, result);

        // Remove this worker from our workers list
        this.workers = this.workers.filter(w => w !== worker);

        // Run the next task if we have one
        this.runNext();
      });

      worker.on('error', (err) => {
        console.error(`Worker for task ${task.id} had an error:`, err);
        this.workers = this.workers.filter(w => w !== worker);
        this.runNext();
      });

      worker.on('exit', (code) => {
        if (code !== 0) {
          console.error(`Worker for task ${task.id} exited with code ${code}`);
        }
      });
    }
  }

// Usage
const queue = new TaskQueue();

// Add some tasks
for (let i = 1; i <= 10; i++) {
  queue.addTask({
    id: i,
    type: 'calculation',
    data: Array.from({ length: 1000000 }, () => Math.random())
  });
}
// In worker.js
process.on('message', (task) => {
  console.log(`Worker ${process.pid} received task ${task.id}`);

  // Simulate CPU-intensive work
  let result;

  if (task.type === 'calculation') {
    // For example, find sum and average
    const sum = task.data.reduce((acc, val) => acc + val, 0);
    const avg = sum / task.data.length;

    result = { sum, avg };
  }

  // Send result back to parent
  process.send({ taskId: task.id, result });

  // Exit this worker
  process.exit(0);
});

Tashqi ilovalarni ishga tushirish

const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs');

// Function to convert a video using ffmpeg
function convertVideo(inputFile, outputFile, options = {}) {
  return new Promise((resolve, reject) => {
    // Make sure input file exists
    if (!fs.existsSync(inputFile)) {
      return reject(new Error(`Input file ${inputFile} does not exist`));
    }

    // Prepare ffmpeg arguments
    const args = ['-i', inputFile];

    if (options.scale) {
      args.push('-vf', `scale=${options.scale}`);
    }

    if (options.format) {
      args.push('-f', options.format);
    }

    args.push(outputFile);

    // Spawn ffmpeg process
    const ffmpeg = spawn('ffmpeg', args);

    // Collect output for logging
    let stdoutData = '';
    let stderrData = '';

    ffmpeg.stdout.on('data', (data) => {
      stdoutData += data;
    });

    ffmpeg.stderr.on('data', (data) => {
      stderrData += data;
    });

    // Handle process completion
    ffmpeg.on('close', (code) => {
      if (code === 0) {
        resolve({
          inputFile,
          outputFile,
          stdout: stdoutData,
          stderr: stderrData
      });
      } else {
        reject(new Error(`ffmpeg exited with code ${code}\n${stderrData}`));
      }
    });

    // Handle process errors
    ffmpeg.on('error', reject);
   });
}

// Example usage (commented out)
/*
convertVideo('input.mp4', 'output.webm', {
  scale: '640:480',
  format: 'webm'
})
  .then(result => {
    console.log('Video conversion successful!');
    console.log(`Output file: ${result.outputFile}`)
;   })
  .catch(error => {
    console.error('Video conversion failed:', error.message);
  });
*/

Eng yaxshi amaliyotlar

  • Kirishni tozalash: Buyruqlar kiritish hujumlarining oldini olish uchun har doim foydalanuvchi kiritishlarini, ayniqsa exec() bilan tozalang.
  • Resurslarni boshqarish: Bolalar jarayonlari tomonidan foydalaniladigan resurslarni (xotira, fayl deskriptorlari) kuzatib boring va boshqaring.
  • Xatolarni hal qilish: Har doim bolalar jarayonlari uchun xatoliklarni to‘g‘ri hal qiling
  • Choose the Right Method:
    • Chiqish cheklangan oddiy buyruqlar uchun exec() dan foydalaning
    • Uzoq davom etadigan jarayonlar yoki katta natijalar uchun spawn() dan foydalaning
    • CPU intensiv Node.js operatsiyalari uchun fork() dan foydalaning
  • Tozalash: Agar kerak bo‘lmasa, bolalar jarayonlarini to‘g‘ri yo‘q qiling
  • Bir vaqtning o‘zida chegaralanish: Tizimning ortiqcha yuklanishini oldini olish uchun bir vaqtning o‘zida bo‘lgan bolalar jarayonlari sonini boshqaring

Ogohlantirish: Haddan tashqari ko‘p bolalar jarayonlarini ishga tushirish tizim resurslarini tezda ishlatishi mumkin. Har doim tezlikni cheklash va parallellik nazoratini amalga oshiring.


Xavfsizlik masalalari

  • Buyruqni kiritish: Hech qachon tozalanmagan foydalanuvchi ma’lumotlarini bevosita exec() yoki spawn() ga o‘tkazmang
  • Muhit o‘zgaruvchilari: Muhit o‘zgaruvchilarini bolalar jarayonlariga o‘tkazishda ehtiyot bo‘ling
  • Faylga kirish: Bolalar jarayonlari uchun ruxsatlarni tushuning
  • Resurs cheklovlari: Bolalar jarayonlari uchun kutish vaqti va xotira chegaralarini joriy qilishni ko‘rib chiqing



W3Schools Pathfinder

Yutuqlaringizni kuzating – bu bepul!