我创建了一个Node.js脚本,它创建了大量随机生成的测试数据,我想将它写入Redis DB。我正在使用redis客户端库和async库。最初,我尝试在生成测试数据的redisClient.hset(...)
循环中执行for
命令,但在一些谷歌搜索之后,我了解到Redis方法是异步的,而for
循环是同步的。在看到StackOverflow上的一些问题后,我无法按照我想要的方式工作。
我可以写一个Redis,而不会出现小数组或更大的数组,例如一个包含100,000个项目的数组。但是,当我有5,000,000个项目的数组时,它不能正常工作。我最终没有足够的内存,因为redis命令似乎正在排队,但是直到async.each(...)
完成并且节点进程没有退出之后才执行。如何调用redisClient.hset(...)
?
这是我正在使用的代码片段。
var redis = require('redis');
var async = require('async');
var redisClient = redis.createClient(6379, '192.168.1.150');
var testData = generateTestData();
async.each(testData, function(item, callback) {
var someData = JSON.stringify(item.data);
redisClient.hset('item:'+item.key, 'hashKey', someData, function(err, reply) {
console.log("Item was persisted. Result: " +reply);
});
callback();
}, function(err) {
if (err) {
console.error(err);
} else {
console.log.info("Items have been persisted to Redis.");
}
});
答案 0 :(得分:0)
您可以调用eachLimit以确保您不会同时执行太多redisClient.hset调用。
为避免溢出调用堆栈,您可以执行setTimeout(callback, 0);
而不是直接调用回调。
编辑:
忘掉我对setTimeout的看法。您需要做的就是在正确的位置调用回调。像这样:
redisClient.hset('item:'+item.key, 'hashKey', someData, function(err, reply) {
console.log("Item was persisted. Result: " +reply);
callback();
});
您可能仍希望使用eachLimit并尝试哪种限制效果最佳。
顺便说一下 - async.each应该仅用于调度javascript事件队列中回调调用的代码(例如,计时器,网络等)。永远不要像在原始代码中那样立即在调用回调的代码上使用它。
编辑:
您可以实现自己的eachLimit函数,而不是数组将生成器作为第一个参数。然后编写生成器函数来创建测试数据。要使其工作,需要使用“node --harmony code.js”运行节点。
function eachLimit(generator, limit, iterator, callback) {
var isError = false, j;
function startNextSetOfActions() {
var elems = [];
for(var i = 0; i < limit; i++) {
j = generator.next();
if(j.done) break;
elems.push(j.value);
}
var activeActions = elems.length;
if(activeActions === 0) {
callback(null);
}
elems.forEach(function(elem) {
iterator(elem, function(err) {
if(isError) return;
else if(err) {
callback(err);
isError = true;
return;
}
activeActions--;
if(activeActions === 0) startNextSetOfActions();
});
});
}
startNextSetOfActions();
}
function* testData() {
while(...) {
yield new Data(...);
}
}
eachLimit(testData(), 10, function(item, callback) {
var someData = JSON.stringify(item.data);
redisClient.hset('item:'+item.key, 'hashKey', someData, function(err, reply) {
if(err) callback(err);
else {
console.log("Item was persisted. Result: " +reply);
callback();
}
});
}, function(err) {
if (err) {
console.error(err);
} else {
console.log.info("Items have been persisted to Redis.");
}
});