简体   繁体   English

Node.js中类似C的互斥锁

[英]c-like mutex in nodejs

I am trying to achieve c-like wait and signal in node.js. 我正在尝试在node.js中实现类似c的等待和信号。 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. 请记住,我是node.js的新手,并且对JavaScript不太熟练。

My thing is : 我的事情是:

  • I have a python interactive process running on the server. 我在服务器上运行了python交互式进程。

  • A client makes a Ajax to the server, which is in turn asking this python process by writing on his stdin. 客户端向服务器制作一个Ajax,服务器随后通过在其stdin上进行编写来询问此python进程。 The http response object is kept in a variable. http响应对象保存在变量中。

  • 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 : 我想使这个“ python part”成为原子的,这意味着:

  • If another request is received while the python process is already running, do a wait. 如果在python进程已经运行时收到另一个请求,请等待。 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. 同样,在二进制信号量或互斥锁和互斥锁中,与P和V的行为相同。

So if you advanced nodejs users have a suggestion ? 那么,如果您对高级nodejs感兴趣,用户会提出建议吗? I looked in npm but found nothing but Promise-like mutex, which I think does not really fit my situation. 我查看了npm,但是除了Promise式的互斥锁外什么也没找到,我认为这并不适合我的情况。

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 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 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;

You 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. 当您通过stdout收到响应时,请检查队列是否包含另一个请求和进程。

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: 一种选择是产生多个python进程:

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 : 为此,您需要公开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 . 另外,如果您确实只想要一个python进程,则应使用异步队列而不是互斥锁 There is no mutex lock in nodejs as there is no parallel code execution. 由于没有并行代码执行,因此nodejs中没有互斥锁。 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
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM