并发活动的语言同步('map-reduce')在节点中?
编辑
感谢答复,我有一个工作版本。 问题结束时的代码; 感谢@estus和@Jared的帮助。
原来的问题
我的方式进入节点,并试图获得并发处理。 从一个简单的例子开始:给定两个文件的名字,确定哪个更大。 常规(顺序)解决scheme:
var fs = require('fs'); var fname1=process.argv[2] var fname2=process.argv[3] var stats1 = fs.statSync(fname1) size1=stats1["size"] var stats2 = fs.statSync(fname2) size2=stats2["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") }
现在假设我想并行统计文件*。 我可以将代码转换为使用asynchronousstat
function:
var fs = require('fs'); var fname1=process.argv[2] var fname2=process.argv[3] fs.stat(fname1, function doneReading(err, stats) { size1=stats["size"] fs.stat(fname2, function doneReading(err, stats) { size2=stats["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") } }) })
然而:
- 它的可读性较差;
- 如果我想比较> 2个文件,它将不能很好地扩展;
- 不知道它甚至会并行统计文件(我不清楚如何后台线程工作)。
所以,具体来说,以下的惯用方法是:
- 然后同时产生多个操作
- 一旦完成,使用他们的综合结果?
也许承诺可能是一个候选人? Promise.all
看起来像等待所有承诺的方式,但不清楚如何实际使用他们的结果。
谢谢。
解
'use strict'; const co = require('co'); const fs = require('fs-promise'); var fname1=process.argv[2] var fname2=process.argv[3] co(function* () { let res = yield [fs.stat(fname1), fs.stat(fname2)]; let size1 = res[0]["size"] let size2 = res[1]["size"] if(size1 > size2) { console.log(fname1 + " is bigger") } else if (size2 > size1) { console.log(fname2 + " is bigger") } else { console.log("The files are the same size") } })
它非常可读,简洁,完全没有callback的麻烦。 并可以随时扩展比较n个文件。
–
*是的,我知道这种情况下不需要这样做。 目的是用一个简单的例子来理解模式。
fs.stat(fname1, function doneReading(err, stats) { ... fs.stat(fname2, function doneReading(err, stats) { ...
仍然是顺序的而不是并行的,与fs.statSync
的区别在于它的fs.stat
是非阻塞的。
现代节点中build议的“可读”方法是promise和co
。 fs.stat
可能被promisified(与pify
或蓝鸟的Promise.promisify
/ Promise.promisifyAll
)。 或者可以使用一些现有的promisified fs
包,如fs-promise
。
以上代码的顺序和非阻塞替代可能如下所示:
'use strict'; const co = require('co'); const fs = require('fs-promise'); co(function* () { let stat1 = yield fs.stat(fname1); let stat2 = yield fs.stat(fname2); ... });
如果我们想使它平行, Promise.all
步骤如下:
co(function* () { let [stat1, stat2] = yield [fs.stat(fname1), fs.stat(fname2)]; // a shortcut for // let [stat1, stat2] = yield Promise.all([fs.stat(fname1), fs.stat(fname2)]); ... });
除了estus的出色答案之外,这可能更容易些:
let stat = Promise.promisify(fs.stat.bind(fs)); Promise.all(arrOfPaths.map(stat)).then(arrOfResults => { // do stuff });
如上所述,您需要编写promisify函数或使用添加它的库。
这是一个示例实现:
const promisify = fn => { return function(...args) { return new Promise((resolve, reject) => { fn.apply(this, [...args, (err, ...rest) => { if (err) { reject(err); } let result; switch (rest.length) { case 0: result = true; break; case 1: result = rest[0]; break; default: result = rest; break; } resolve(result); }]); }); }; };