Node.js有限并行性存疑:示例代码是否真的实现并行?
关于Node.js异步流控制示例的疑问解答
你完全没理解错——这段代码根本不是并行执行的,官方文档这里的描述明显有问题,这就是个标准的串行执行逻辑。
为什么是串行?
看核心的serial函数逻辑:每次调用dispatch发送邮件后,只有等到它的异步回调执行完毕,才会再次调用serial发起下一次邮件发送。也就是说,同一时间永远只有一个sendMail请求在运行,必须等上一个彻底完成,才会启动下一个,完全是串行的执行流程,和“有限并行”没有任何关系。
原示例代码
let successCount = 0; function final() { console.log(`dispatched ${successCount} emails`); console.log('finished'); } function dispatch(recipient, callback) { // `sendEmail` is a hypothetical SMTP client sendMail( { subject: 'Dinner tonight', message: 'We have lots of cabbage on the plate. You coming?', smtp: recipient.email, }, callback ); } function sendOneMillionEmailsOnly() { getListOfTenMillionGreatEmails(function (err, bigList) { if (err) throw err; function serial(recipient) { if (!recipient || successCount >= 1000000) return final(); dispatch(recipient, function (_err) { if (!_err) successCount += 1; serial(bigList.pop()); }); } serial(bigList.pop()); }); } sendOneMillionEmailsOnly();
真正的有限并行实现思路
如果要实现有限并行(比如同时最多运行5个邮件发送任务),需要维护一个“任务池”,当一个任务完成后立刻补充新的任务,保持并行数量在设定的上限。简单示例如下:
let successCount = 0; const MAX_PARALLEL_TASKS = 5; // 控制最大并行数 let activeTaskCount = 0; let currentListIndex = 0; function final() { console.log(`dispatched ${successCount} emails`); console.log('finished'); } function dispatch(recipient, callback) { sendMail( { subject: 'Dinner tonight', message: 'We have lots of cabbage on the plate. You coming?', smtp: recipient.email, }, callback ); } function sendOneMillionEmailsWithLimit() { getListOfTenMillionGreatEmails(function (err, bigList) { if (err) throw err; function runNextTask() { // 终止条件:已发送够100万,或者列表已遍历完,且所有活跃任务都结束 if (successCount >= 1000000 || currentListIndex >= bigList.length) { if (activeTaskCount === 0) final(); return; } activeTaskCount++; const recipient = bigList[currentListIndex++]; dispatch(recipient, function (_err) { activeTaskCount--; if (!_err) successCount += 1; runNextTask(); // 当前任务完成,立刻启动下一个 }); } // 初始化启动最大并行数的任务 for (let i = 0; i < MAX_PARALLEL_TASKS; i++) { runNextTask(); } }); } sendOneMillionEmailsWithLimit();
内容的提问来源于stack exchange,提问作者Truc Truca
相关产品推荐
相关产品推荐

