2013-05-28 26 views
0

我有一个循环函数,我正在测试我的一个路线。问题是我称之为挂起所有网络调用,直到完成该功能。我想知道如何在处理这个时不锁定节点。表示js挂在重功能直到它完成

app.get('/populate', routes.populate); 

exports.populate = function(req, res, next){ 

    for(i = 0; i < 100000; i++){ 
     var tmp = new Encounters(); 

     tmp.kareoId = '1234'; //mock.Address.zipCode(); 

     tmp.patient.fullName = 'Vartan Arabyan'; //mock.Name.findName(); 
     tmp.patient.dob = Date.now(); 
     tmp.patient.kareoId = '12312'; //mock.Address.zipCode(); 

     tmp.physician.fullName = "Dr." + 'Vartan Arabyan'; //mock.Name.findName(); 
     tmp.physician.kareoId = '12312'; //mock.Address.zipCode(); 

     tmp.appointmentType = "NCV Upper"; 
     tmp.appointment = Date.now(); 

     tmp.save(function(err){ 
      if (err) throw err; 
     }); 

     if(i == 99999){ 
      res.send(200, 'Fake Data Loaded'); 
     } 
    } 
}; 
+0

试着在你的递增计数器保存(只有当'save'成功返回创建下一个'Encounters'实例)。实际上,您的代码会创建10000个对象并排队10000次保存。 – WiredPrairie

回答

0

您需要在回调中调用您的tmp变量设置。 App.VERB()是非阻塞的。我对mongoose不熟悉,但是所有带有tmp变量的代码似乎都是阻塞的。没有回调,所以变量是逐个设置的,当你写这几千次时变得明显。

+0

你能给我一个你的建议的例子吗? –

0

此循环会阻止事件循环,直到迭代100,000次。试试这个:

app.get('/populate/:counter', routes.populate); 

exports.populate = function(req, res, next){ 

    var tmp = new Encounters(); 

    tmp.kareoId = '1234'; //mock.Address.zipCode(); 

    tmp.patient.fullName = 'Vartan Arabyan'; //mock.Name.findName(); 
    tmp.patient.dob = Date.now(); 
    tmp.patient.kareoId = '12312'; //mock.Address.zipCode(); 

    tmp.physician.fullName = "Dr." + 'Vartan Arabyan'; //mock.Name.findName(); 
    tmp.physician.kareoId = '12312'; //mock.Address.zipCode(); 
    tmp.appointmentType = "NCV Upper"; 
    tmp.appointment = Date.now(); 

    tmp.save(function(err){ 
     if (err) throw err; 
    }); 

    if(req.param('counter') == 99999){ 
     return res.send(400, 'Fake Data Loaded'); 
    } 
    res.send(200, 'Send me more Data'); 
}; 

然后,在一个循环中发送100,000个请求到/ populate /:counter路由。您可以使用另一个实例节点创建的虚假请求,你可以做这样的事情:

var http = require('http'); 

var options = { 
    hostname: 'localhost', 
    port: 3000, // I assumed that your express is running on port 3000... 
    method: 'GET' 
}; 

var req; 
for (var i = 0; i < 100000; i++) { 
    options.path = '/populate/' + i; 
    req = http.request(options, function(res) { 
     res.setEncoding('utf8'); 
     if (res.statusCode == 400) { 
      // Handle 'Fake Data Loaded' 
      console.log('Fake data loaded..'); 
     } 
     else 
      console.log('Still not there yet! Send more data...') 
     res.on('data', function (data) { 
      console.log(data); 
     }); 
    }); 

    req.on('error', function(e) { 
     console.log('problem with request: ' + e.message); 
    }); 

    req.end(); 
}; 

你要注意的是,其他节点实例将同时使100000个http请求被阻止。不过,在处理这些请求您的Express实例不会被阻塞......

+0

这就是很多http协议开销 - 为什么不用异步路径和循环来关闭? –

+0

当然,编写一个异步工厂会起作用...... – lyxio

+0

它几乎是完全相同的东西,用较少的协议绒毛阻碍进入 –

0

重写它是无阻塞和使用回调

即。许多小的快速功能,而不是一个大的慢速功能。

你应该尽量避免慢速繁重的功能。把它分解成小任务。

它'挂起'的原因是因为node.js是单线程的。我建议阅读node.js Event Loop,回调以及如何编写非阻塞。

如果您有很多小功能,express可以在第一个“仍在运行”时响应请求。将事件循环看作是按顺序执行的任务数组。

使用aysnc.parallel().series() - 文档和堆的例子github repo。如果执行顺序很重要,使用series(),如果不是,则使用parallel()。

在你的例子中,你想快速插入100k行。 创建一个插入一行并在完成时调用next()回调函数的函数。 创建一个完成的功能,运行您的res.send() 使用async.times()执行创建功能,然后完成后运行done功能。

See async.times() documentation on their github repo

// Pretend this is some complicated async factory 
var createUser = function(id, callback) { 
    callback(null, { 
    id: 'user' + id 
    }) 
} 
// generate 5 users 
async.times(5, function(n, next){ 
    createUser(n, function(err, user) { 
     next(err, user) 
    }) 
}, function(err, users) { 
    // we should now have 5 users 
}); 
+0

使用'async.times'只会缓解这个问题。这里的问题是循环的大小(100K),即使使用'async.times',也很容易让事件循环饿死([gist](https://gist.github.com/robertklep/5668245)):在我的测试中,超时需要几乎3倍的时间) – robertklep

+0

对数据库执行任何100k次的操作,并且需要一些时间:) –

+0

从内存中,'.times()'是串行的 - 你可以运行100x在一个'.parallel()'中有一个潜在的速度提升 –

相关问题