Skip to content

পারফরমেন্স অপ্টিমাইজেশন

Sharp ইতিমধ্যে একটি উচ্চ-পারফরমেন্স ইমেজ প্রসেসিং লাইব্রেরি, তবে কিছু অপ্টিমাইজেশন কৌশলের মাধ্যমে আপনি আরও পারফরমেন্স উন্নত করতে পারেন।

বেঞ্চমার্ক টেস্ট

অন্যান্য ইমেজ প্রসেসিং লাইব্রেরির তুলনায় Sharp-এর পারফরমেন্স সুবিধা:

  • ImageMagick-এর চেয়ে 4-5 গুণ দ্রুত
  • GraphicsMagick-এর চেয়ে 4-5 গুণ দ্রুত
  • কম মেমরি ব্যবহার
  • স্ট্রিম প্রসেসিং সমর্থন

মেমরি অপ্টিমাইজেশন

স্ট্রিম প্রসেসিং ব্যবহার করুন

বড় ফাইলের জন্য, স্ট্রিম প্রসেসিং ব্যবহার করে মেমরি ব্যবহার উল্লেখযোগ্যভাবে হ্রাস করা যায়:

javascript
import fs from 'fs';

// ❌ সুপারিশ করা হয় না: পুরো ফাইল মেমরিতে লোড করুন
const buffer = fs.readFileSync('large-image.jpg');
await sharp(buffer).resize(800, 600).toFile('output.jpg');

// ✅ সুপারিশ করা হয়: স্ট্রিম প্রসেসিং ব্যবহার করুন
fs.createReadStream('large-image.jpg')
  .pipe(sharp().resize(800, 600).jpeg())
  .pipe(fs.createWriteStream('output.jpg'));

চাঙ্ক প্রসেসিং

অতিবড় ফাইলের জন্য, চাঙ্ক প্রসেসিং করা যায়:

javascript
import fs from 'fs';

async function processLargeFile(inputPath, outputPath, chunkSize = 1024 * 1024) {
  const pipeline = sharp()
    .resize(800, 600)
    .jpeg({ quality: 80 });

  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(inputPath, { highWaterMark: chunkSize });
    const writeStream = fs.createWriteStream(outputPath);

    readStream
      .pipe(pipeline)
      .pipe(writeStream)
      .on('finish', resolve)
      .on('error', reject);
  });
}

await processLargeFile('large-input.jpg', 'output.jpg');

সময়মতো মেমরি মুক্ত করুন

javascript
// প্রসেসিং সম্পন্ন হলে সময়মতো পরিষ্কার করুন
async function processImage(inputPath, outputPath) {
  const sharpInstance = sharp(inputPath);
  
  try {
    await sharpInstance
      .resize(800, 600)
      .jpeg({ quality: 80 })
      .toFile(outputPath);
  } finally {
    // ম্যানুয়ালি পরিষ্কার করুন (যদিও Node.js স্বয়ংক্রিয়ভাবে গার্বেজ কালেকশন করবে)
    sharpInstance.destroy();
  }
}

কনকারেন্সি অপ্টিমাইজেশন

কনকারেন্সি সংখ্যা নিয়ন্ত্রণ করুন

javascript
async function processWithConcurrency(files, concurrency = 3) {
  const results = [];
  
  for (let i = 0; i < files.length; i += concurrency) {
    const batch = files.slice(i, i + concurrency);
    const batchPromises = batch.map(file => 
      sharp(file)
        .resize(300, 200)
        .jpeg({ quality: 80 })
        .toFile(`processed-${file}`)
    );
    
    const batchResults = await Promise.all(batchPromises);
    results.push(...batchResults);
  }
  
  return results;
}

const files = ['file1.jpg', 'file2.jpg', 'file3.jpg', 'file4.jpg'];
await processWithConcurrency(files, 2);

Worker থ্রেড ব্যবহার করুন

CPU-ইনটেনসিভ টাস্কের জন্য, Worker থ্রেড ব্যবহার করা যায়:

javascript
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';

if (isMainThread) {
  // মেইন থ্রেড
  async function processWithWorkers(files, numWorkers = 4) {
    const workers = [];
    const results = [];
    
    for (let i = 0; i < numWorkers; i++) {
      const worker = new Worker('./image-worker.js', {
        workerData: { files: files.slice(i * Math.ceil(files.length / numWorkers), (i + 1) * Math.ceil(files.length / numWorkers)) }
      });
      
      worker.on('message', (result) => {
        results.push(result);
      });
      
      workers.push(worker);
    }
    
    await Promise.all(workers.map(worker => new Promise(resolve => worker.on('exit', resolve))));
    return results;
  }
  
  const files = ['file1.jpg', 'file2.jpg', 'file3.jpg'];
  await processWithWorkers(files);
} else {
  // Worker থ্রেড
  const { files } = workerData;
  
  for (const file of files) {
    await sharp(file)
      .resize(300, 200)
      .jpeg({ quality: 80 })
      .toFile(`processed-${file}`);
  }
  
  parentPort.postMessage('done');
}

ক্যাশে অপ্টিমাইজেশন

প্রসেসিং ফলাফল ক্যাশে করুন

javascript
import crypto from 'crypto';
import fs from 'fs';

class ImageCache {
  constructor(cacheDir = './cache') {
    this.cacheDir = cacheDir;
    if (!fs.existsSync(cacheDir)) {
      fs.mkdirSync(cacheDir, { recursive: true });
    }
  }

  generateCacheKey(inputPath, options) {
    const content = JSON.stringify({ inputPath, options });
    return crypto.createHash('md5').update(content).digest('hex');
  }

  async getCachedResult(cacheKey) {
    const cachePath = `${this.cacheDir}/${cacheKey}.jpg`;
    if (fs.existsSync(cachePath)) {
      return cachePath;
    }
    return null;
  }

  async setCachedResult(cacheKey, resultPath) {
    const cachePath = `${this.cacheDir}/${cacheKey}.jpg`;
    fs.copyFileSync(resultPath, cachePath);
  }

  async processImage(inputPath, options) {
    const cacheKey = this.generateCacheKey(inputPath, options);
    const cached = await this.getCachedResult(cacheKey);
    
    if (cached) {
      console.log('ক্যাশে ফলাফল ব্যবহার করুন');
      return cached;
    }

    const outputPath = `output-${Date.now()}.jpg`;
    await sharp(inputPath)
      .resize(options.width, options.height)
      .jpeg({ quality: options.quality })
      .toFile(outputPath);

    await this.setCachedResult(cacheKey, outputPath);
    return outputPath;
  }
}

const cache = new ImageCache();
await cache.processImage('input.jpg', { width: 300, height: 200, quality: 80 });

অ্যালগরিদম অপ্টিমাইজেশন

উপযুক্ত রিসাইজ অ্যালগরিদম নির্বাচন করুন

javascript
// ফটোর জন্য, lanczos3 কার্নেল ব্যবহার করুন
await sharp('photo.jpg')
  .resize(800, 600, { kernel: sharp.kernel.lanczos3 })
  .toFile('photo-resized.jpg');

// আইকন বা লাইন আর্টের জন্য, nearest কার্নেল ব্যবহার করুন
await sharp('icon.png')
  .resize(32, 32, { kernel: sharp.kernel.nearest })
  .toFile('icon-resized.png');

// দ্রুত প্রসেসিং প্রয়োজন এমন ইমেজের জন্য, cubic কার্নেল ব্যবহার করুন
await sharp('image.jpg')
  .resize(300, 200, { kernel: sharp.kernel.cubic })
  .toFile('image-resized.jpg');

JPEG কোয়ালিটি অপ্টিমাইজ করুন

javascript
// ইমেজ কনটেন্ট অনুযায়ী কোয়ালিটি অ্যাডজাস্ট করুন
async function optimizeJPEGQuality(inputPath, outputPath) {
  const metadata = await sharp(inputPath).metadata();
  
  // ইমেজ আকার অনুযায়ী কোয়ালিটি অ্যাডজাস্ট করুন
  let quality = 80;
  if (metadata.width > 1920 || metadata.height > 1080) {
    quality = 85; // বড় ইমেজের জন্য উচ্চ কোয়ালিটি ব্যবহার করুন
  } else if (metadata.width < 800 && metadata.height < 600) {
    quality = 75; // ছোট ইমেজের জন্য নিম্ন কোয়ালিটি ব্যবহার করা যায়
  }
  
  await sharp(inputPath)
    .jpeg({ 
      quality,
      progressive: true, // প্রগ্রেসিভ JPEG
      mozjpeg: true      // mozjpeg অপ্টিমাইজেশন ব্যবহার করুন
    })
    .toFile(outputPath);
}

নেটওয়ার্ক অপ্টিমাইজেশন

বিভিন্ন আকার প্রি-জেনারেট করুন

javascript
const sizes = [
  { width: 320, suffix: 'sm' },
  { width: 640, suffix: 'md' },
  { width: 1024, suffix: 'lg' },
  { width: 1920, suffix: 'xl' }
];

async function pregenerateSizes(inputPath) {
  const promises = sizes.map(size => 
    sharp(inputPath)
      .resize(size.width, null, { fit: 'inside' })
      .jpeg({ quality: 80 })
      .toFile(`output-${size.suffix}.jpg`)
  );
  
  await Promise.all(promises);
}

await pregenerateSizes('input.jpg');

আধুনিক ফরম্যাট ব্যবহার করুন

javascript
// বিভিন্ন ব্রাউজার সমর্থনের জন্য একাধিক ফরম্যাট জেনারেট করুন
async function generateModernFormats(inputPath) {
  const promises = [
    // ফলব্যাক হিসেবে JPEG
    sharp(inputPath)
      .resize(800, 600)
      .jpeg({ quality: 80 })
      .toFile('output.jpg'),
    
    // আধুনিক ব্রাউজারের জন্য WebP
    sharp(inputPath)
      .resize(800, 600)
      .webp({ quality: 80 })
      .toFile('output.webp'),
    
    // সর্বশেষ ব্রাউজারের জন্য AVIF
    sharp(inputPath)
      .resize(800, 600)
      .avif({ quality: 80 })
      .toFile('output.avif')
  ];
  
  await Promise.all(promises);
}

মনিটরিং এবং ডিবাগিং

পারফরমেন্স মনিটরিং

javascript
import { performance } from 'perf_hooks';

async function measurePerformance(fn) {
  const start = performance.now();
  const result = await fn();
  const end = performance.now();
  
  console.log(`এক্সিকিউশন সময়: ${end - start}ms`);
  return result;
}

await measurePerformance(async () => {
  await sharp('input.jpg')
    .resize(800, 600)
    .jpeg({ quality: 80 })
    .toFile('output.jpg');
});

মেমরি ব্যবহার মনিটরিং

javascript
import { performance } from 'perf_hooks';

function getMemoryUsage() {
  const usage = process.memoryUsage();
  return {
    rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
    heapTotal: `${Math.round(usage.heapTotal / 1024 / 1024)}MB`,
    heapUsed: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
    external: `${Math.round(usage.external / 1024 / 1024)}MB`
  };
}

console.log('প্রসেসিংয়ের আগে মেমরি ব্যবহার:', getMemoryUsage());

await sharp('input.jpg')
  .resize(800, 600)
  .jpeg({ quality: 80 })
  .toFile('output.jpg');

console.log('প্রসেসিংয়ের পরে মেমরি ব্যবহার:', getMemoryUsage());

সেরা অনুশীলন সারাংশ

  1. বড় ফাইলের জন্য স্ট্রিম প্রসেসিং ব্যবহার করুন
  2. কনকারেন্সি সংখ্যা নিয়ন্ত্রণ করুন
  3. প্রসেসিং ফলাফল ক্যাশে করুন
  4. উপযুক্ত রিসাইজ অ্যালগরিদম নির্বাচন করুন
  5. আউটপুট ফরম্যাট এবং কোয়ালিটি অপ্টিমাইজ করুন
  6. সাধারণ আকার প্রি-জেনারেট করুন
  7. পারফরমেন্স মেট্রিক্স মনিটর করুন

পারফরমেন্স তুলনা

অপারেশনSharpImageMagickGraphicsMagick
রিসাইজ100ms450ms420ms
ফরম্যাট কনভার্শন80ms380ms360ms
ফিল্টার প্রয়োগ120ms520ms480ms
মেমরি ব্যবহারকমবেশিবেশি

পরবর্তী ধাপ

Apache 2.0 লাইসেন্সের অধীনে রিলিজ করা হয়েছে।