Sunny-117 / js-challenges

✨✨✨ Challenge your JavaScript programming limits step by step

Home Page:https://juejin.cn/column/7244788137410560055

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

处理高并发, 100 条数据,带宽为 10, 跑满带宽

Sunny-117 opened this issue · comments

处理高并发, 100 条数据,带宽为 10, 跑满带宽
function asyncPool(limit,dates,fn) {
  let count = 0;
  const exec = [];
  const values = [];
  const _asyncPool = () => {
    if (count === dates.length) {
      return Promise.resolve();
    }

    const item = dates[count++];
    const p = Promise.resolve().then(()=>fn(item));
    values.push(p);

    const _p = p.then(()=>exec.splice(exec.indexOf(_p), 1));
    exec.push(_p);
    
    let next = Promise.resolve();
    if (exec.length >= limit) {
      next = Promise.race(exec);
    }
    return next.then(()=>_asyncPool());
  }
  return _asyncPool().then(()=>Promise.all(values));
}
async function asyncPool(poolLimit, array, iteratorFn) {
    let poolList = [] // 并发队列
    let ret = [] // 所有的任务
    for(let i of array) {
        let p = new Promise.resolve(iteratorFn(i))  // 添加Promise处理,统一处理非Promise的任务
        ret.push(p)
        let _p = p.then(() => { poolList.splice(poolList.indexOf(_p), 1)}) // 任务完成将任务推出队列
        poolList.push(_p) // 将任务放到并发队列中去

        if(poolList.length >= poolLimit) { // 当任务数达到并发上限
            await Promise.race(poolList) // 等待队列中的任务完成
        }
    }
    return Promise.all(ret) // 返回任务执行结果
}
function task() {
  return new Promise(resolve => {
    setTimeout(() => {
      const timestamp = Date.now() / 1000 | 0
      console.log(timestamp)
      resolve(timestamp)
    }, 1000)
  })
}

async function concurrent(tasks, max = 10) {
  const results = []
  const poolList = new Set()

  for (const task of tasks) {
    if (poolList.size === max) {
      await Promise.race(poolList).catch(console.log)
    }

    const p = task()
    const cb = () => poolList.delete(p)

    p.then(cb, cb)
    poolList.add(p)
    results.push(p)
  }

  return Promise.allSettled(results)
}

concurrent([task, task, task, task, task, task, task, task, task], 2)
  .then(res => {
    console.log(res)
  })
commented
// 处理高并发, 100 条数据,带宽为 10, 跑满带宽
const REQ_NUM = 100
const msg = new Array(REQ_NUM).fill('')
for (let i = 0; i < REQ_NUM; i++) {
    msg[i] = `第${i + 1}条数据`
}

const getAxios = (msg) => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(msg)
        }, 1000 * Math.random())
    })
}

const asyncProcess = async(limit = 10) => {
    const tasks = []
    const resArr = []
    for (let i = 0; i < REQ_NUM; i++) {
        const curTask = getAxios(msg[i]).then(res => {
            resArr.push(res)
            tasks.splice(tasks.indexOf(curTask), 1)
        })
        tasks.push(curTask)
        if (tasks.length === limit) {
            await Promise.race(tasks)
        }
    }
    await Promise.allSettled(tasks)
    return resArr
}

asyncProcess().then(res => {
    console.log(res)
})
//模拟请求
function mockRequest<T = unknown>(text: T): Promise<string> {
  return new Promise((resolve) => {
    const start = performance.now();
    setTimeout(() => {
      resolve(`${text}:${performance.now() - start}`);
    }, 20 + Math.random() * 200);
  });
}
type AsyncTask = () => Promise<unknown>;
// 请求任务
class RequestTask {
  private runningTasks: Set<Promise<unknown>> = new Set();

  private todoTasks: AsyncTask[] = [];
  constructor(private config: { limit: number } = { limit: 10 }) {}

  tryRun() {
    if (this.runningTasks.size >= this.config.limit) {
      Promise.race(this.runningTasks).then(() => this.tryRun());
    } else if (this.todoTasks.length > 0) {
      const task = this.todoTasks.shift()!;
      const taskP = task().then(() => {
        this.runningTasks.delete(taskP);
      });
      this.runningTasks.add(taskP);
    }
  }
  run(task: AsyncTask): ReturnType<AsyncTask> {
    return new Promise((resolve) => {
      this.todoTasks.push(async () => {
        const res = await task();
        resolve(res);
      });
      this.tryRun();
    });
  }
}

const task = new RequestTask({limit:10});
Promise.all(
  Array(100)
    .fill(0)
    .map((_, i) =>
      task
        .run(() => mockRequest(i))
        .then((res) => {
          console.log("child", res);
          return res;
        })
    )
).then((res) => {
  console.log("all", res);
});