node.js - 与单独运行相比,为什么异步运行多个数据抓取任务需要更多时间?
问题描述
我在 Node.JS 中使用 puppeteer 来运行一个数据抓取任务,该任务试图一次从多个页面获取数据。每个页面都有一个选项卡式结构,我需要从 4 个选项卡中获取数据。我单击一个选项卡并使用“等待”从选项卡获取数据。最后,我将获得的数据写入excel文件。除了完成所需的时间外,代码可以正常工作。如果我为单个 URL 运行代码,则需要 7 到 10 秒来获取每个 URL 的数据并将其写入 Excel 文件。但是,如果我在“for”循环中运行 16 个 URL 的代码,则几乎需要 30 到 33 秒。我认为完成这项工作需要不到 12 秒的时间,因为它是异步运行的。在一个 for 循环中运行 16 个任务期间,CPU 中的所有线程都被占用 100%。代码太长,我这里只写代码结构:
由于我不知道如果任务失败如何重复任务,我编写了 2 个 try-catch 结构,因为它们是嵌套的。
for (i = 0; i < URL.length; i++) {
try {
UpdateTable(URL[i], i, 1);
} catch (e) {
try {
UpdateTable(URL[i], i, 2);
} catch (e) {
UpdateTable(URL[i], i, 3);
}
}
}
async function UpdateTable(URL, ii, Ind) {
return new Promise((resolve, reject) => {
var temp = [];
temp = (async () => {
console.time(("i: " + ii + ": " + Ind).toString());
console.timeLog("i: " + ii + ": " + Ind);
try {
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.goto(URL); //Bourse
//Tab 1:
await page.evaluate(() => {
document.getElementsByClassName('torq')[0].click();
})
await page.waitForSelector("tr.ev", {visible: true}).then(() => {
});
var temp = [];
var temp_1col = [];
var temp1_1col = [];
temp = await page.evaluate(() => {
//
//
//
//
//
}
//Tab 2:
await page.evaluate(() => {
document.getElementsByClassName('vio')[0].click();
})
await page.waitForSelector("div.CalMon", {visible: true}).then(() => {
});
var temp1 = [];
temp1 = await page.evaluate(() => {
//
//
//
//
//
}
//Tab 3:
await page.evaluate(() => {
document.querySelectorAll('a.re')[0].click();
})
var tt = await page.evaluate(() => {
return document.getElementById("d12").innerText;
})
while (tt === undefined || tt === "") {
tt = await page.evaluate(() => {
return document.getElementById("d12").innerText;
})
}
var temp2 = [];
temp2 = await page.evaluate(() => {
//
//
//
//
//
}
//Tab 4:
await page.evaluate(() => {
document.querySelectorAll('a.ye')[0].click();
})
await page.waitForXPath("//div[@class='Main']//span//tr[5]//td[2]", {visible: true}).then(() => {
});
var temp4 = await page.evaluate(() => {
//
//
//
//
//
}
//Writing to Excel file Using: "exceljs" module:
const sheet8 = workbook3.addWorksheet("Adjusted");
sheet8.views = [{rightToLeft: true}];
sheet8.addRows(temp_adj);
await browser.close();
console.timeEnd(("i: " + ii + ": " + Ind).toString());
return temp;
} catch (e) {
console.log("Error In: " + URL);
}
})();
});
}
我测量了每个循环完成的时间:
i: 0: 1: 0.065ms
i: 1: 1: 0.020ms
i: 2: 1: 0.004ms
i: 3: 1: 0.004ms
i: 4: 1: 0.028ms
i: 5: 1: 0.007ms
i: 6: 1: 0.003ms
i: 7: 1: 0.018ms
i: 8: 1: 0.018ms
i: 9: 1: 0.005ms
i: 10: 1: 0.003ms
i: 11: 1: 0.003ms
i: 12: 1: 0.003ms
i: 13: 1: 0.003ms
i: 14: 1: 0.003ms
i: 15: 1: 0.003ms
i: 13: 1: 13728.609ms
i: 0: 1: 14846.398ms
i: 15: 1: 14857.476ms
i: 4: 1: 18383.652ms
i: 6: 1: 18504.466ms
i: 10: 1: 22255.862ms
i: 5: 1: 29188.227ms
i: 7: 1: 29187.398ms
i: 14: 1: 30093.722ms
i: 8: 1: 30297.994ms
i: 2: 1: 30381.256ms
i: 1: 1: 30426.768ms
i: 11: 1: 30644.432ms
i: 12: 1: 30677.942ms
i: 3: 1: 30689.566ms
i: 9: 1: 30710.694ms
正如您在时间日志中看到的,URL[13] 需要 13728.609 毫秒,而如果我运行此 URL 的代码,则只需 8000 毫秒。为什么与单个任务相比,一起运行 16 个任务需要更多时间?为什么异步运行需要 30710.694 毫秒,而任务所需的最长时间低于 10000 毫秒?
如果你能帮助我解决这个挑战,我将不胜感激。
解决方案
在类似的情况下,我观察到内存耗尽并且系统开始交换。在内存和磁盘之间移动数据很慢,而且很快就达到了似乎需要永远完成的地步。100% 的 CPU 利用率很好,但也要注意使用了多少内存。
推荐阅读
- haskell - 为什么使用 applicative functors 不如 monads 进行整数除法?
- groovy - 如何在 java 中调用完整的 groovy 语句?
- html - 当任何一个弹性项目对于弹性容器来说太宽时,使所有弹性项目都换行(如弹性方向:列)
- jackson - Spring 在何处/何时使用项目配置中定义的 Jackson2ObjectMapperBuilderCustomizer bean?
- php - 执行 LOAD DATA INFILE 时如何将 VARCHAR 日期转换为标准 MYSQL 日期格式
- nasm - 汇编从 STDIN 直接读取字节到寄存器
- c++ - 在声明中初始化时,字符数组上 cout 的奇怪输出?仅当我在此之后声明另一个数组时才会发生
- mongodb - MongoDB过滤器查询日期数组返回空数组
- c# - 如何使用 VSTO 以编程方式显示“通过电子邮件发送日历”对话框?
- azure-cognitive-search - Azure 索引中的项目顺序与原始 JSON 文件不同