最近遇到个问题,在for loop里面调用http.get请求,测试发现,会慢个几ms然后请求才会发出去,代码如下:
async function run() {
for (let i = 0; i < 100; i++) {
for (let j = 0; j < 40; j++) {
let local_ts = Date.now();
let cid = 'cid_' + i * 1000 + j;
let url = `http://127.0.0.1:8890/ts?id=${cid}&ts=${local_ts}`;
http.get(url).then(ret => {
let server_ts = ret.split(' ')[1];
let finish_ts = Date.now();
console.log(cid, ret, 'elapsed', finish_ts - local_ts, 'server_diff', server_ts - local_ts, 'finish_diff', finish_ts - server_ts);
});
console.log(cid, 'fired', local_ts, Date.now());
}
await Sleep(3000);
}
}
run();
调用的是个http服务,传本地的timestamp给他,他返回server的timestamp,方便我们计算网络的latency。
这时候就非常疑惑了,为什么server收到我们发送的请求都要6-10ms,这中间网络肯定没这么慢。
怀疑是event loop的锅,首先看了下http的实现,在最后会调用一个process.nextTick
event loop里面分了很多个loop,代码可以参考
r = uv__loop_alive(loop);
if (!r)
uv__update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
uv__update_time(loop);
uv__run_timers(loop);
ran_pending = uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
uv__io_poll(loop, timeout);
uv__run_check(loop);
uv__run_closing_handles(loop);
if (mode == UV_RUN_ONCE) {
uv__update_time(loop);
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
break;
}
而process.nextTick是在这里面任意一个loop结束后就执行的,所以我们的请求其实都堆积到了sleep那儿,因为http get都在for loop里面,所以这里我们如果要立马执行http get,需要切出我们的loop回到event loop. 在循环立马加入一个await Sleep(0)
async function run() {
for (let i = 0; i < 100; i++) {
for (let j = 0; j < 40; j++) {
let local_ts = Date.now();
let cid = 'cid_' + i * 1000 + j;
let url = `http://127.0.0.1:8890/ts?id=${cid}&ts=${local_ts}`;
http.get(url).then(ret => {
let server_ts = ret.split(' ')[1];
let finish_ts = Date.now();
console.log(cid, ret, 'elapsed', finish_ts - local_ts, 'server_diff', server_ts - local_ts, 'finish_diff', finish_ts - server_ts);
});
console.log(cid, 'fired', local_ts, Date.now());
await Sleep(0);
}
await Sleep(3000);
}
}
run();
这时候堆积之后再请求的问题就解决了,不过问题还是有,一毫秒左右才一个请求,感觉太慢。
PS. Sleep代码
const Promise = require('bluebird');
module.exports = function(duration) {
return new Promise(resolve => {
setTimeout(() => {
resolve(null);
}, duration);
});
}
Top comments (0)