I am trying to achieve c-like wait and signal in node.js. I have in mind a binary semaphore or a mutex. Please keep in mind I am new to node.js and not very skilled in javascript.
My thing is :
I have a python interactive process running on the server.
A client makes a Ajax to the server, which is in turn asking this python process by writing on his stdin. The http response object is kept in a variable.
Then I am intercepting stdout which contains my answer, and sending it into the kept response object.
I would like to make this 'python part' atomic, which means :
If another request is received while the python process is already running, do a wait. Otherwise the request will be lost.
When the stdout triggers, send a signal to free the access.
Again, same behaviour as P and V in a binary semaphore or mutex lock and mutex unlock.
So if you advanced nodejs users have a suggestion ? I looked in npm but found nothing but Promise-like mutex, which I think does not really fit my situation.
Maybe I am wrong and there is a way. Anyway I look forward to reading your suggestions or workaround. Thank you.
Here is the relevant sample code.
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;
I am trying to achieve c-like wait and signal in node.js. I have in mind a binary semaphore or a mutex. Please keep in mind I am new to node.js and not very skilled in javascript.
My thing is :
I have a python interactive process running on the server.
A client makes a Ajax to the server, which is in turn asking this python process by writing on his stdin. The http response object is kept in a variable.
Then I am intercepting stdout which contains my answer, and sending it into the kept response object.
I would like to make this 'python part' atomic, which means :
If another request is received while the python process is already running, do a wait. Otherwise the request will be lost.
When the stdout triggers, send a signal to free the access.
Again, same behaviour as P and V in a binary semaphore or mutex lock and mutex unlock.
So if you advanced nodejs users have a suggestion ? I looked in npm but found nothing but Promise-like mutex, which I think does not really fit my situation.
Maybe I am wrong and there is a way. Anyway I look forward to reading your suggestions or workaround. Thank you.
Here is the relevant sample code.
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;
Share
Improve this question
edited Feb 1, 2018 at 13:49
Bastien Meta
asked Feb 1, 2018 at 13:31
Bastien MetaBastien Meta
331 silver badge4 bronze badges
2
-
How do you know when the python instance returned a response? Does it write sth to
stdout
? – Jonas Wilms Commented Feb 1, 2018 at 14:09 - yes it does, and what it writes is sent in http response – Bastien Meta Commented Feb 1, 2018 at 15:36
2 Answers
Reset to default 9You don’t need a mutex or semaphore, cause in node you have only one thread. All you need is to store the requests in a queue (which can be an array) if there is any request being processed. When you receive a response via stdout, check if the queue contains another request and process.
You can have an mutex-like abstraction based on promises. Here is an example:
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;
}
}
}
Usage example:
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();
};
I used this code to test:
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);
}
})();
... and got this result:
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'
One option would be to spawn multiple python processes:
router.post('/getParams', function(req, res, next){
in_data = req.body.imgBase64;
pycaffe.create().queryParams(res, in_data);
});
For that you need to expose create
:
return {
getInstance: function() {
if(!pycaffeInstance) {
pycaffeInstance = create();
}
return pycaffeInstance;
},
create // expose create here
};
Alternatively, if you really only want one python process, you should use an asynchronous queue instead of a mutex lock. There is no mutex lock in nodejs as there is no parallel code execution. A sample async queue would look like this:
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;
}
}
And that can be used like this:
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
});
});
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742279678a4414253.html
评论列表(0条)