【问题标题】:How can I limit the number of child processes in imagemin-mozjpeg?如何限制 imagemin-mozjpeg 中的子进程数量?
【发布时间】:2018-09-30 17:19:46
【问题描述】:

我正在使用 imagemin-mozjpeg,它使用 mozjpeg 二进制文件来压缩图像。

问题是我在 nodejs 网络服务器中使用它。

现在是这样的:

  1. 我正在使用“请求”模块 (fs.createReadStream) 上传 JPEG 图像。

  2. Multer 处理流并将其保存在缓冲区(内存存储)中。

  3. 然后将缓冲区传递给imagemin进行压缩。

  4. 然后将压缩缓冲区写入文件。 (example.jpg)

一切正常。

这里的问题是,对于每个请求,都会产生一个新的 mozjpeg 二进制子进程 cjpeg。

1 个子进程正在消耗 12.5 MB 内存(对于 .5 MB 文件)。

如果我同时有 50 个请求,则大约为 700 MB,因为对于 50 个图像,有 50 个子进程。

有没有办法可以限制子进程的数量? (该库正在使用“execa”模块)或仅生成 4-5 个子进程,它们对所有请求进行压缩。

谢谢

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");
                });

        }

【问题讨论】:

    标签: node.js compression imagemin mozjpeg


    【解决方案1】:

    解决这个问题的主要概念是限制对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])
          }
        })
    

    请注意,由于您的调度程序是从 Array 扩展而来的,因此您可以使用任何 Array 方法来管理您的任务,例如pop() 丢弃最后一个任务,shift() 丢弃第一个任务,unshift(newTask) 在调度程序队列的开头插入一个新任务。

    【讨论】:

    • 感谢您的概念。现在我要尝试和实验。 :)
    • req.files 是一个空对象。任何想法?我认为是因为它还没有通过multer。
    • 然后在 multer 中间件之后注册你的任务调度器中间件。如果你使用 express,express 中间件会按照你调用express.use()的顺序执行。
    • 我已更新我的代码以包含 expressmulter。试试看有没有问题;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    相关资源
    最近更新 更多