关于promise:使用Promiserace实现控制并发

34次阅读

共计 1473 个字符,预计需要花费 4 分钟才能阅读完成。

之前做过一个 Node.js 实现分片上传 的性能。过后前端采纳文件切片后并发上传,大大提高了上传的速度,应用 Promise.race() 治理并发池,无效防止浏览器内存耗尽。

当初的问题:Node.js 服务端合并大文件分片 内存耗尽导致服务重启

服务端代码

const ws = fs.createWriteStream(`${target}/${filename}`); // 创立将要写入文件分片的流
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`); // 读取到分片文件名的列表 [1,2,3...] 每个分片 1M 大小

// 2. 不会阻塞 EventLoop
bufferList.forEach((hash, index) => {fs.readFile(`${STATIC_TEMPORARY}/${filename}/${index}`, (err, data) => {ws.write(data);
  });
});

服务器配置:RAM:1024MB 1vCPU(运行了一些其余服务)

测试发现只有上传的文件超过 300M,在合并分片时就会导致内存耗尽服务重启,根本无法实现分片合并。

解决方案:能不能在循环中管制读取文件的并发数呢? 这样就不会有大量文件同时读取到内存中导致服务解体了。

尝试像前端那样应用 Promise.race 管制:

const ws = fs.createWriteStream(`${target}/${filename}`); // 创立将要写入文件分片的流
const bufferList = fs.readdirSync(`${STATIC_TEMPORARY}/${filename}`); // 读取到分片文件名的列表 [1,2,3...] 每个分片 1M 大小

// Promise.race 并发管制
const pool = [];
let finish = 0; // 曾经写入实现的分片数量

// 应用 Promise 包裹读取文件的异步操作
const PR = (index) => {return new Promise((resolve) => {fs.readFile(`${STATIC_TEMPORARY}/${filename}/${index}`, (err, data) => {ws.write(data)
      resolve({});
    });
  });
};

(async function easyRead() {for (let i = 0; i < bufferList.length; i ++) {const task = PR(i).then(val => {
      finish+=1
      const index = pool.findIndex(t => t === task);
      pool.splice(index);
      if (finish === bufferList.length) {ws.close();
      }
    });
    pool.push(task);
    if (pool.length === 1) { // 这里并发数量只能是 1 否则分片写入是乱序的 格局会被损坏
      await Promise.race(pool);
    }
  }
})()

这时神奇的事件就产生了,咱们在 for 循环中应用了 Promise.race() 管制了同一时间读入到内存中的文件数量。

再次测试,服务曾经不会在合并分片时解体,即便 1 个 G 的文件分片也能够在 3 秒左右合并实现。

总结

晓得 Promise.race() 的人很多,这样的面试题也很多,然而能使用到实际中解决理论的问题却不是很多。

心愿本文能够帮到你。

文章首发于 IICOOM- 技术博客《应用 Promise.race() 实现管制并发》

正文完
 0