nodejs

时间:2018-02-01 13:31:17

标签: javascript python c node.js asynchronous

我正在尝试在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;

2 个答案:

答案 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
  });
});