简体   繁体   中英

How to spawn a new Python child process in Node.js after the first one ends?

I use the output of a Python script in my node.js app.

However, I need to query it another time (and, possibly, several times).

I cannot do this because the Python process ends and cannot be restarted. I tried to reassign the variable, but it doesn't work. How to launch the Python script again? Here is my code:

var spawn = require('child_process').spawn,
interval_data = [1,2,4,5,6,7],
interval_dataString = '';

var py = undefined

startPython()

py.stdout.on('data', function(data){
  interval_dataString += data.toString();
  console.log(interval_dataString)
});
  

py.stdout.on('end', function(){

  console.log('Alpha Component =',interval_dataString);
  
  setTimeout(() => {
    startPython()
  },1000)

});


function startPython() {
  py = undefined
  py = spawn('python', ['dfa.py'])
  py.stdin.write(JSON.stringify(interval_data));
  py.stdin.end();
}

Here's the Python code:

## compute_input.py

import sys, json, numpy as np

#Read data from stdin
def read_in():
    
    lines = sys.stdin.readlines()
    #Since our input would only be having one line, parse our JSON data from that
    
    return json.loads(lines[0])
    
    #lines = "[1,2]" # for testing
    #return json.loads(lines) # for testing

def main():
    #get our data as an array from read_in()
    lines = read_in()

    #create a numpy array
    np_lines = np.array(lines)

    #use numpys sum method to find sum of all elements in the array
    lines_sum = np.sum(np_lines)

    #return the sum to the output stream
    print(lines_sum)

#start process
if __name__ == '__main__':
    main()

You override the child process. So you can no longer use the original object (event emitter).

Its simpler then you tought maybe:)

Just call/move the event emitter stuff inside the "start" function. So every time you spawn the child, you use the new child object/event emitter.

const { spawn } = require("child_process");

const interval_data = [1, 2, 4, 5, 6, 7]
const interval_response = [];

// use this as exit strategie
var should_restart = true;


function start() {

    // spawn python child
    let child = spawn("python3", ["dfa.py"]);

    // would be better to work on buffer objects
    // create on final child/python exit a string out of the buffer
    child.stdout.on("data", (data) => {
        interval_response.push(data.toString());
    });

    // listen for the close event
    child.on("close", () => {
        if (should_restart) {

            // feedback
            console.log("Alpha Component =", interval_response.join());

            setTimeout(() => {
                start();
            }, 1000)

        } else {

            // nope, not now!
            console.log("DIE!", interval_response);
        
            // Do what ever you want with the result here

        }
    });

    // write stuff to python child process
    child.stdin.write(JSON.stringify(interval_data));

}

start();


// let the programm run for min. 5sec
setTimeout(() => {
    should_restart = false;
}, 5000);

Tested with your python code.

node index.js
Alpha Component = 3

Alpha Component = 3
,3

Alpha Component = 3
,3
,3

Alpha Component = 3
,3
,3
,3

DIE! [ '3\n', '3\n', '3\n', '3\n', '3\n' ]

I thought you actually read in your python script from stdin. (And not only a dummy function)

But for the node part it should not make any difdrence.

Tested on Ubuntu 18.04 x64, node: v13.14.0, python: 3.6.9.

EDIT :

Created based on your python snippet, a script that reads from stdin and create a sum out of all numbers passed:

import sys, json

def main():

    data = sys.stdin.read()
    data = json.loads(data)

    #print("debug:", data)

    chunks_sum = sum(data)

    #print("debug", chunks_sum)

    sys.stdout.write(str(chunks_sum))

#start process
if __name__ == '__main__':
    main()

Modified start function:

function start() {

    // spawn python child
    let child = spawn("python3", ["dfa.py"]);

    // would be better to work on buffer objects
    // create on final child/python exit a string out of the buffer
    child.stdout.on("data", (data) => {

        // since your python code just create
        // a sum of all numbers, store the 
        // returend stuff as number
        interval_response.push(Number(data));

    });

    // listen for the close event
    child.on("close", () => {
        if (should_restart) {

            // feedback
            console.log("Alpha Component =", interval_response);

            setTimeout(() => {
                start();
            }, 1000)

        } else {

            // nope, not now!
            console.log("DIE!", interval_response);

            // create sum of all sum chunks from python
            // not sure what you want to do with the "interval_response" array
            // just for demo purpose
            let sum = interval_response.reduce((pv, cv) => pv + cv, 0);

            console.log("Total sum", sum);

        }
    });

    // write stuff to python child process
    //child.stdin.write();

    child.stdin.end(JSON.stringify(interval_data));

}

Changed child.stdin.write to child.stdin.end , so does python now it can "start" and dosnt has to wait for more data.

Note: i dont know how IPC/stdio "buffering" work. Perhaps you expirence some fishy things if you work with large data.

More, we store the data from python that is writen to "stdout" as number in the array interval_response , since you just calculate the total sum of the data we write to "stdin".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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