下面有什么比赛条件吗?
我在我的快递服务器中有下面的代码(为了简洁起见,请把它剪下来)。 我有一个共同的对象,我正在添加/修改/阅读三个不同的宁静的终点。 由于nodejs中的所有http请求都是asynchronous的,所以我可以同时获得请求和请求。 所以,虽然PUT发生,但让我们说状态不更新,我的GET可以得到一个稍微陈旧的回应?
根据我的理解,我的testing显示这里没有竞争条件。 因为更新results
对象是一个同步操作,所有的asynchronous操作应该等待它。 有人可以帮助更好地解释这是否正确?
var obj = {}; const exec = require('child_process').exec; app.post('/foo', (req, res) => { var result = {}; result.id = generateSomeRandomId(); result.failed = 0; result.status = 'running' //execute some command and update result const child = exec('some command'); child.stdout.on('data', (data) => { //some logic }); child.stderr.on('data', (data) => { result.failed = result.failed + 1; }); child.on('close', (code, signal) => { if (signal !== null && signal !== undefined) { result.status = 'cancelled'; } else { result.status = 'completed'; result.runtime = calculateRunTime(); } }); result.pid = child.pid; obj[result.id] = result; res.send(result); } app.put('/foo/:id', (req, res) => { var result = obj[req.params.id]; if (result.status === 'running' && result.pid !== undefined) { kill(result.pid, 'SIGKILL'); result.status = 'cancelled'; result.runtime = calculateRunTime(); } res.send(result); } app.get('/foo/:id', (req, res) => { var result = obj[req.params.id]; res.send(result); }
你没有任何我称之为“竞赛条件”的东西; 这里有一个不确定的因素,但实际上这不太可能是重要的。
它看起来像你的post
开始一个进程,并返回ID,你的put
取消进程,你的get
返回进程的当前状态。 从这我收集,你将永远不能get
直到你的post
完成并提供该ID。
如果你在你的exec
asynchronous监听器完成之前做了一个接收和返回的get
调用,你将得到任何最后的进行中的状态 – 我假设这是devise。 所以这里唯一可能的冲突是如果你打了一个电话来停止你的过程。
当你和你的结果对象进行交互时,你的put
和get
都是同步的,所以无论先接收哪一个,都是先完成的。 您可以忽略进程取消请求,因为它不修改结果对象。 不能保证他们会以客户发送的相同顺序收到,这可能会或可能不会成为您场景中的实际问题。
我相信 (尽pipe我的内存可能是错误的),如果你使用cluster
来处理不同进程中的请求,你将无法通过一个共享对象传递数据,所以任何增加了这种可能性的复杂性已经排除。
所以,networking性能和可靠性的差异是你唯一真正的通配符。 服务器将按照它们进来的顺序处理请求,并给你预期的结果。 如果你只有一个客户端,你可以等到你之前的请求发送下一个请求的响应,这可能会让你的性能变得不可接受,但或多或less的防弹。 否则,只需发送您的请求,不用担心,只要让您的应用程序足够健壮即可识别并处理第二个取消请求,即使您已经取消了该过程。
这只是一个想法,但也许一个承诺可能会在这里有所帮助:
var obj = {}; const exec = require('child_process').exec; app.post('/foo', (req, res) => { var result = {}; result.id = generateSomeRandomId(); result.status = 'running'; const child = exec('some command'); child.stdout.on('data', (data) => { //some logic }); result.promise = new Promise(resolve => { child.stderr.on('data', (data) => { result.failed = result.failed + 1; resolve(false); }); child.on('close', (code, signal) => { // ... resolve(true); }); }); result.pid = child.pid; obj[result.id] = result; res.send(result); } app.get('/foo/:id', (req, res) => { var result = obj[req.params.id]; if(result.status === 'running') { result.promise.then(() => res.send(result)); } else { res.send(result); } }
在这种情况下,只有当child
由错误或“closures”事件完成时,GET才会作出响应。