简体   繁体   English

如何限制imagemin-mozjpeg中子进程的数量?

[英]How can I limit the number of child processes in imagemin-mozjpeg?

I'm using imagemin-mozjpeg which uses mozjpeg binary to compress images. 我正在使用使用mozjpeg二进制文件压缩图像的imagemin-mozjpeg。

The problem is that I'm using it in a nodejs webserver. 问题是我在Node.js Web服务器中使用它。

This is how it works now: 现在是这样的:

  1. I'm uploading a JPEG image using "request" module (fs.createReadStream). 我正在使用“请求”模块(fs.createReadStream)上传JPEG图像。

  2. Multer process the stream the stream and keep it in buffer (memory storage). Multer处理流并将其保留在缓冲区(内存存储)中。

  3. Then pass the buffer to the imagemin to compress. 然后将缓冲区传递给imagemin进行压缩。

  4. The compressed buffer is then written to a file. 然后将压缩的缓冲区写入文件。 (example.jpg) (example.jpg)

Everything works. 一切正常。

The problem here is that for each request, a new child process of mozjpeg binary is spawned, cjpeg. 这里的问题是,对于每个请求,都会生成一个新的mozjpeg二进制子进程cjpeg。

1 child process is consuming 12.5 MB of memory (for a .5 MB file). 1个子进程占用12.5 MB的内存(.5 MB文件)。

If I've 50 requests at the same time, that goes to ~700 MB because for 50 images there are 50 child processes. 如果我同时有50个请求,那将达到〜700 MB,因为对于50张图像,有50个子进程。

Is there a way that I can limit the the number of child processes? 有什么办法可以限制子进程的数量? (the library is using "execa" module) or just spawn 4-5 child process and they do the compression for all the requests. (该库正在使用“ execa”模块)或只是生成4-5个子进程,它们会对所有请求进行压缩。

Thanks 谢谢

if (req.files.myimage[0].buffer) {
            let fileNumber = filesUploaded++;

            imagemin.buffer(req.files.myimage[0].buffer, {
                plugins: [
                    imageminMozjpeg({ quality: 60, progressive: true })
                ]
            })
                .then(file => {
                    fs.writeFile(__dirname + '/uploads/' + uuidv4() + '.jpg', file, 'hex' , function () {
                        res.end("SUCCESS" + fileNumber.toString());
                    });

                })
                .catch(err => {
                    console.log(err);
                    res.end("FAILED");
                });

        }

The main concept to solve this problem is to limit the number of call to the imagemin() (who spawns image processing process). 解决此问题的主要概念是将调用次数限制为imagemin() (产生图像处理过程的调用)。

Maybe you can implement a task scheduling system using a task queue to gather requests and some workers to process the request with imagemin() . 也许您可以使用任务队列来实现一个任务调度系统,以收集请求,并使用一些工作程序使用imagemin()处理请求。

    var multer  = require('multer')
    var upload = multer({ dest: 'your/uploads/' })

    // TaskScheduler, a wrapper of a task array
    class TaskScheduler extends Array {
      constructor (MAX_SLOTS, worker) {
        super()
        this._MAX_SLOTS= MAX_SLOTS
        this._busy_slots= 0
        this._worker= worker
      }

      /**
       * Create new tasks
       */
      push (...tasks) {
        const ret = super.push(...tasks)

        this.run()
        return ret
      }

      /**
       * Run tasks in available slots
       */
      run () {
        // if there are any tasks and available slots
        while (this.length > 0 && this._busy_slots < this._MAX_SLOTS) {
          const firstTask = this.shift()
          this._worker(firstTask).then(() => {
            // release the slot
            this._busy_slots--

            // since a task slot is released
            // call run() again to process another task from the queue
            this.run()
          })
          this._busy_slots++
        }
      }
    }

    // worker is supposed to return a Promise
    const scheduler = new TaskScheduler(5, function (task) {
      return imagemin.buffer(task.buffer, { /* imagemin options */ })
        .then(() => { /* write image files */ })
        .catch(() => { /* error handling */ })
    })

    // schedule the task when there is an incoming request
    // the actual code depends on your web server
    // here what to do in the callback is the point ;)

    // Take express for example, `app` is the express.Application
    app.post('your/end/point', upload.fields([{ name: 'myimage' }]), function (req) {
      if (req.files.myimage[0]) {
        scheduler.push(req.files.myimage[0])
      }
    })

Note that since your scheduler is extended from Array , you can use any Array method to manage your tasks, eg pop() to discard the last task, shift() to discard the first task and unshift(newTask) to insert a new task at the begining of the scheduler queue. 请注意,由于调度程序是从Array扩展的,因此可以使用任何Array方法管理任务,例如pop()丢弃最后一个任务, shift()丢弃第一个任务, unshift(newTask)插入新任务调度程序队列的开始。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM