当我打开几个流时,如何避免使用类似递归的结构,我必须得到一个绝对的end
事件才能完成逻辑。
var someArray = ['file1', 'file2', 'file3'];
someArray.forEach(function( file ) {
fs
.createReadStream( file )
.pipe( /* do some stuff */ )
.on('data', function( usageInfo ) {
// done?
});
}
我有几个文件,我必须通过tp管道一些进程。如何设置一个事件,告诉我何时完成所有事件?
目前我得到的是每个end
事件。
我绝对可以同时启动每个流。我只是需要以某种方式收集结束?
我可以为每个end
事件调用一个函数调用并计算它......虽然听起来很讨厌?...
我觉得有一种方法可以用承诺做到这一点,但我不知道如何。
答案 0 :(得分:3)
使用计数器:
var someArray = ['file1', 'file2', 'file3'];
var still_processing = someArray.length;
someArray.forEach(function( file ) {
fs.createReadStream( file )
.pipe( /* do some stuff */ )
.on('end', function() {
still_processing--;
if (!still_processing) {
// done
}
});
}
这是基本机制。此控制流模式由async.js中的async.parallel()
函数封装:
var someArray = ['file1', 'file2', 'file3'];
var streams_to_process = [];
someArray.forEach(function( file ) {
streams_to_process.push(function(callback) {
var result = "";
fs.createReadStream( file )
.pipe( /* do some stuff */ )
.on('end', function() {
callback(null, result);
});
});
});
async.parallel(streams_to_process, function(err, results) {
// all done
});
在内部,async.parallel使用闭包中捕获的计数器来跟踪所有异步进程(在本例中为'end'事件)的完成时间。
还有其他库。例如,大多数promise表提供了一个.all()
方法,其工作方式相同 - 内部跟踪计数器值并在完成所有操作后触发.then()
回调。
答案 1 :(得分:3)
我觉得有一种方法可以用承诺做到这一点,但我不知道如何。
是的,有。由于promises确实表示异步值,因此您将获得一个流的结束承诺:
void testStorage() {
int nFrames = 512;
int width = 0;
int height = 0;
// 8-bit unsigned char images
Mat frame, floatFrame;
frame = imread("C:/Matlab code/im.png", CV_LOAD_IMAGE_GRAYSCALE);
// convert uchar images to float images
frame.convertTo(floatFrame, CV_32F, 1.0/255.0f);
width = frame.step;
height = frame.rows;
cout << "width: " << width << " height: " << height << endl;
float *gpuBuffer;
float *testImage;
gpuErrchk( cudaMalloc( (void**) &gpuBuffer, sizeof(float) * width * height * nFrames)); // storage init for buffer
gpuErrchk( cudaMemset(gpuBuffer, 0, sizeof(float) * width * height * nFrames)); // set mem to 0
gpuErrchk( cudaMalloc( (void**) &testImage, sizeof(float) * width * height )); // storage init for image
gpuErrchk( cudaMemset(testImage, 0, sizeof(float) * width * height )); // set mem to 0
gpuErrchk( cudaMemcpy( testImage, floatFrame.ptr<float>(), sizeof (float) * width * height, cudaMemcpyHostToDevice) );
// num of threads
dim3 Threads(width);
// num of blocks
dim3 Blocks(height);
for(int i = 0; i < nFrames; i++)
{
copySlice2Volume2<<< Blocks, Threads >>> (gpuBuffer, testImage, width, height, i);
}
gpuErrchk( cudaDeviceSynchronize() ); // error here
printf("Cuda status2: %s\n", cudaGetErrorString( cudaGetLastError() ) );
gpuErrchk( cudaFree(gpuBuffer) );
gpuErrchk( cudaFree(testImage) );
}
可以像var p = new Promise(function(resolve, reject) {
fs.createReadStream(file)
.on('error', reject)
.pipe(/* do some stuff */)
.on('end', resolve)
.on('error', reject); // call reject(err) when something goes wrong
});
一样使用。
现在,如果您创建多个promises,一个用于数组中的filename,则所有流将并行运行并在完成后解析它们各自的承诺。然后,您可以使用wikipedia entry for Graham scan来收集 - 阅读“等待” - 将每个结果的所有结果转换为一系列结果的新承诺。
p.then(functio(usageInfo) { console.log("stream ended"); })