如何安全地执行操作,然后从.txt文件中asynchronous插入250,000多个字,而不会导致堆栈溢出?

我正在尝试做的事情是用单词的.txt文件读取,在换行符处将它们分开,然后对构造数组中的每个单词执行对该单词(与我正在使用的Word模式匹配)的操作确定每个单词的字母数,如“单词(0 A,0 B,1 W,1 O,1 R,1 D,OZ等)”,然后将每个单词插入到数据库中。

下面是数据库条目(models / words.js)的Word“形状”的mongoose模式

var restful = require('node-restful'); var mongoose = restful.mongoose; // MongoDB Schema var wordSchema = new mongoose.Schema({ code: String, word: String, lettersCount: { 'a': Number, 'b': Number, 'c': Number, 'd': Number, 'e': Number, 'f': Number, 'g': Number, 'h': Number, 'i': Number, 'j': Number, 'k': Number, 'l': Number, 'm': Number, 'n': Number, 'o': Number, 'p': Number, 'q': Number, 'r': Number, 's': Number, 't': Number, 'u': Number, 'v': Number, 'w': Number, 'x': Number, 'y': Number, 'z': Number } }); // Return model module.exports = restful.model( 'Words', wordSchema ); 

现在,我的数据在文件dictionaries/words.txt

在名为server.js的主文件中,我调用了这个函数:

 populateDictionary(); 

tasks/populateDictionary.js文件具有以下function来执行数据库条目:

 var populateDictionary = function(dict) { Word.remove().exec(); fs.readFileAsync('dictionaries/words.txt', 'utf8').then(function(data, err) { if (err) throw err; var dictionary = data.split('\n'); for (var i = 0; i < dictionary.length; i++) { var entry = new Word({ word: dictionary[i], lettersCount: { 'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 0, 'g': 0, 'h': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 0, 'o': 0, 'p': 0, 'q': 0, 'r': 0, 's': 0, 't': 0, 'u': 0, 'v': 0, 'w': 0, 'x': 0, 'y': 0, 'z': 0 } }); for (var j = 0; j < entry.word.length; j++) { entry.lettersCount[entry.word[j]]++; } console.log(entry); entry.save(); } }); }; 

所以,我对数据库相当陌生,但认为这里有一个很好的解决scheme,只是不知道是什么…我基本上是一个巨大的调用堆栈,它正在崩溃我的电脑。 我正在寻找正确的方式来做这种事情。 谢谢!

我会build议asynchronous库。 它有许多有用的方法。 我用下面的async.eachLimit将asynchronous操作限制为提供的数字。

 clearDictionary(function(err){ if(err){ throw err; } else{ populateDictionary(); } }) 

由于remove也是一个io调用,因此在移动到下一个部分之前应该等待操作结束。 这就是为什么包装在上面的clearDictionary 。 定义是:

 var async = require("async"); var clearDictionary = funtion(done) { Word.remove().exec(function(err){ if(err){ done(err); } else{ done(); } }); } var populateDictionary = function() { fs.readFileAsync('dictionaries/words.txt', 'utf8').then(function(data, err) { if (err) throw err; var dictionary = data.split('\n'); async.eachLimit(dictionary, 20, funtion(word, callback){ var entry = new Word({ word: word, lettersCount: getLetterCountObj() }); countLetters(entry); entry.save(function(err){ if(err){ return callback(err); } else{ return callback(); } }); }, function(err){ if(err){ throw err } else{ console.log("Dictionary populated!"); } }) }); }; var getLetterCountObj = function(){ return { 'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 0, 'g': 0, 'h': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 0, 'o': 0, 'p': 0, 'q': 0, 'r': 0, 's': 0, 't': 0, 'u': 0, 'v': 0, 'w': 0, 'x': 0, 'y': 0, 'z': 0 } } var countLetters = function (entry){ for (var j = 0; j < entry.word.length; j++) { entry.lettersCount[entry.word[j]]++; } } 

我不是很熟悉你使用的确切技术,但从结构/逻辑stream程的angular度来看,这可能会有所帮助:

我认为你的问题可能是你在处理之前将整个文件parsing到内存中:实际上,你只需要一次处理一个单词,这是很重要的。 一些快速谷歌search引导我到这篇文章,这使得它看起来像你可以从你的文件中读取一行,计算它,插入你的形状,然后移动到下一个单词,应该防止你吃了大量的内存。

您可以使用nsynjs顺序执行IO调用和逻辑的混合 。 以下是代码需要如何转换的步骤:

第1步:用callback将慢速函数包装到nsynjs-aware包装中:

dbWrappers.js:

 // wrapper for remove exports.remove = function (ctx, collection) { collection.remove().exec(function(err){ ctx.resume(err); }); }; exports.remove.nsynjsHasCallback = true; // wrapper for save exports.save = function (ctx, entry) { entry.save(function(err){ ctx.resume(err); }); }; exports.save.nsynjsHasCallback = true; 

对于readFileAsync,你可以使用这个包装: https : //github.com/amaksr/nsynjs/blob/master/wrappers/nodeFsReadFile.js

第2步。写下你的逻辑,就好像它是同步的,并把它放到函数中:

 var populateDictionary = function(Word, dbWrappers, readFile) { dbWrappers.remove(nsynjsCtx,dict); // use wrapper .remove from above, // nsynjs will wait until callback in the wrapper complete var data = readFile(nsynjsCtx, 'path').data; // use wrapper for fs.readFile var dictionary = data.split('\n'); for (var i = 0; i < dictionary.length; i++) { var entry = new Word({ word: dictionary[i], lettersCount: { 'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0, 'f': 0, 'g': 0, 'h': 0, 'i': 0, 'j': 0, 'k': 0, 'l': 0, 'm': 0, 'n': 0, 'o': 0, 'p': 0, 'q': 0, 'r': 0, 's': 0, 't': 0, 'u': 0, 'v': 0, 'w': 0, 'x': 0, 'y': 0, 'z': 0 } }); for (var j = 0; j < entry.word.length; j++) { entry.lettersCount[entry.word[j]]++; } console.log(entry); dbWrappers.save(nsynjsCtx,entry); // use wrapper '.save' from step 1 } }; 

第3步。通过naynjs以同步方式运行该函数:

 var dbWrappers = require('dbWrappers'); var readFile = require('nodeFsReadFile').readFile; var populateDictionary = function(Word, dbWrappers, readFile) { .... } nsynjs.run(populateDictionary,{},Word, dbWrappers, readFile, function(){ console.log('loading done'); }) 

看到类似的例子https://github.com/amaksr/nsynjs/tree/master/examples/node-mysql (它插入任何数量的logging到MySQL)。