3
votes

I have a script that runs for a long time. It generates an output. I am running this script from nodejs using child_process. How do I send the output of this script soon as it starts executing and do not wait for the script to complete. The code that I currently have waits for the script to complete and then outputs all the stdout at once on nodejs console.

Sample script:

import time

if __name__ == '__main__':
    for i in range(5):
        time.sleep(1)
        print("Hello how are you " + str(i))

nodejs code:

var spawn = require('child_process').spawn,
    ls    = spawn('python', ['path/test.py']);

ls.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

ls.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

ls.on('close', function (code) {
  console.log('child process exited with code ' + code);
});

console.log waits for the script to complete and then outputs

Hello how are you 1
Hello how are you 2
Hello how are you 3
Hello how are you 4
Hello how are you 5

in one shot. Is there anyway I can achieve sending stdout immediately as its written until the child process stops?

1
You are going to run into buffering issues here. - James Mills
python output is beffered? try to flash it import sys and sys.stdout.flush() after each print - befzz
It's not Python output that's buffered (yes you can flush it) but the OS will also buffer the output as well! Read: turnkeylinux.org/blog/unix-buffering - James Mills
I understand thats the difference between node's spawn and exec. Spawn - Abhishek Kusnoor

1 Answers

0
votes

The short answer is:

You need to reopen sys.stdout in non-bufering mode.

Example:

import os
import sys

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

So your program would look like this:

import os
import sys
import time

if __name__ == '__main__':
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    for i in range(5):
        time.sleep(1)
        sys.stdout.write("Hello how are you " + str(i))
        sys.stdout.flush()