我正在尝试在node.js中实现类似c的等待和信号。我想到了二进制信号量或互斥量。请记住,我是node.js的新手,并且不是非常熟练的javascript。
我的意思是:
我在服务器上运行了一个python交互过程。
客户端向服务器发出Ajax,然后通过写入他的stdin来询问这个python进程。 http响应对象保存在变量中。
然后我拦截了包含我的答案的stdout,并将其发送到保存的响应对象中。
我想把这个'python part'原子化,这意味着:
如果在python进程已经运行时收到另一个请求,请等待。否则请求将丢失。
当stdout触发时,发送信号以释放访问权限。
再次,与二进制信号量或互斥锁和互斥锁解锁中的P和V行为相同。
那么如果您使用高级nodejs用户有建议吗?我在npm看了一下,但发现了类似Promise的互斥锁,但我认为它并不适合我的情况。
也许我错了,有办法。 无论如何,我期待着阅读您的建议或解决方法。 谢谢。
以下是相关的示例代码。
route.js
var express = require('express');
var router = express.Router();
var pycaffe = require('./pycaffe');
var py = pycaffe.getInstance();
router.post('/getParams', function(req, res, next){
in_data = req.body.imgBase64;
py.queryParams(res, in_data);
});
pycaffe.js
const { spawn } = require('child_process');
var pycaffe = (function () {
var pycaffeInstance;
function create () {
var response;
console.log('Loading nets...');
const defaults = {
cwd: './nets',
env: process.env
};
var py = spawn('python', ['-i', 'deploy.py'], defaults);
py.stdout.on('data', function(data){
console.log(`stdout: ${data}`);
var fig = JSON.parse(data);
if(response !== undefined)
//send http response
response.send(fig)
//mutex.unlock()
});
function queryParams(res, data) {
//mutex.lock()
response = res;
py.stdin.write("query_params('"+data+"')\n");
}
return {
queryParams: queryParams
};
}
return {
getInstance: function() {
if(!pycaffeInstance) {
pycaffeInstance = create();
}
return pycaffeInstance;
}
};
})();
module.exports = pycaffe;
答案 0 :(得分:1)
您不需要互斥锁或信号量,因为在节点中您只有一个线程。如果有任何请求正在处理,您只需要将请求存储在队列(可以是数组)中。当您通过stdout收到响应时,请检查该队列是否包含其他请求和进程。
您可以根据承诺获得类似互斥的抽象。这是一个例子:
class Mutex {
constructor () {
this.queue = [];
this.locked = false;
}
lock () {
return new Promise((resolve, reject) => {
if (this.locked) {
this.queue.push([resolve, reject]);
} else {
this.locked = true;
resolve();
}
});
}
release () {
if (this.queue.length > 0) {
const [resolve, reject] = this.queue.shift();
resolve();
} else {
this.locked = false;
}
}
}
用法示例:
const mutex = new Mutex();
// using promise syntax
const handleRequest = () => {
mutex.lock().then(() => {
// do something here
mutex.release();
})
};
// using async syntax
const handleRequest = async () => {
await mutex.lock();
// do something here
mutex.release();
};
我用这段代码测试:
const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms));
let processNumber = 1;
const startProcess = async (mutex) => {
const thisProcessId = processNumber++;
console.log(new Date(), `started process ${thisProcessId}`);
await mutex.lock();
console.log(new Date(), `after lock ${thisProcessId}`);
await delay(3000);
mutex.release();
console.log(new Date(), `finished process ${thisProcessId}`);
};
(() => {
const mutex = new Mutex();
for (let i = 0; i < 5; i++) {
setTimeout(() => startProcess(mutex), Math.random() * 10000);
}
})();
......得到了这个结果:
2018-02-01T19:02:36.418Z 'started process 1'
2018-02-01T19:02:36.421Z 'after lock 1'
2018-02-01T19:02:38.565Z 'started process 2'
2018-02-01T19:02:39.426Z 'finished process 1'
2018-02-01T19:02:39.426Z 'after lock 2'
2018-02-01T19:02:40.048Z 'started process 3'
2018-02-01T19:02:42.309Z 'started process 4'
2018-02-01T19:02:42.428Z 'finished process 2'
2018-02-01T19:02:42.428Z 'after lock 3'
2018-02-01T19:02:43.200Z 'started process 5'
2018-02-01T19:02:45.429Z 'finished process 3'
2018-02-01T19:02:45.429Z 'after lock 4'
2018-02-01T19:02:48.433Z 'finished process 4'
2018-02-01T19:02:48.433Z 'after lock 5'
2018-02-01T19:02:51.438Z 'finished process 5'
答案 1 :(得分:0)
一种选择是生成多个python进程:
router.post('/getParams', function(req, res, next){
in_data = req.body.imgBase64;
pycaffe.create().queryParams(res, in_data);
});
为此,您需要公开create
:
return {
getInstance: function() {
if(!pycaffeInstance) {
pycaffeInstance = create();
}
return pycaffeInstance;
},
create // expose create here
};
或者,如果您真的只需要一个python进程,则应使用异步队列而不是互斥锁。 nodejs中没有互斥锁,因为没有并行代码执行。示例异步队列如下所示:
class AsyncQueue {
constructor(task) {
this.task = task;
this.queue = [];
}
push(el){
this.queue.push(el);
this.start();
}
async start(){
if(this.running) return;
this.running = true;
let el;
while(el = this.queue.shift()){
await this.task(el);
}
this.running = false;
}
}
这可以这样使用:
function pyRequest({res, data}){
py.requestParams(res, data);
return new Promise(resolve => res.on("data", resolve));
}
const pyQueue = new AsyncQueue(pyRequest);
router.post('/getParams', function(req, res, next){
pyQueue.push({
data: req.body.imgBase64,
res
});
});