TCL make use of pipe and fileevent to maintain subprocess

Advertisements

I’m trying to setup a demo for subprocess management in tcl. This is what I have done so far

proc receive {chan work_pool channel_id finish} {
    upvar 1 work_pool tmp_pool
    upvar 1 finish tmp_finish
    gets $chan line
    puts $line
    if {[eof $chan]} {
        close $chan
        # remove idx from work pool
        set idx [lsearch $tmp_pool $channel_id]
        set tmp_pool [lreplace $tmp_pool $idx $idx]
        if { [llength $tmp_pool] } {
        } else {
            set tmp_finish 1
        }
    }
}


set command1 {cmd /c "python py_script.py -n PRO1 -l 10"} 
set channel1 [open |[concat $command1 2>@1]]


fconfigure $channel1 -blocking 0 -buffering line

set finish 0
set work_pool [list 1]

fileevent $channel1 readable [list receive $channel1 $work_pool 1 $finish]

vwait finish

This script invokes a command in windows system which executes a python script to print counter value( in this case, it counts to ten)
a fileevent is used to attach a callback proc named "receive" to retrieve python stdout, then, print/puts in tcl process. When the EOF is detected, the callback proc will set finish to 1, which leads to the end of the whole process.

the python script contains below code, which simply count value to args.limit with a 1 second step.

import argparse, time
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--name", type=str, default="default",
                    help="name")
parser.add_argument("-l", "--limit", type=int, default=300,
                    help="count limit")
args = parser.parse_args()
a=0
while(1):
    time.sleep(1)
    a=a+1
    print(f"{args.name}:timer value: {a}")
    if a>=args.limit:
        break
  

I expect the python script will print each number to stdout with an 1 second interval. Therefore, tcl should also retrieve and print these numbers with one per second frequency.
for example

PRO1:timer value: 1
(1s)
PRO1:timer value: 2
(1s)
PRO1:timer value: 3
(1s)
PRO1:timer value: 4
(1s)
PRO1:timer value: 5
(1s)
PRO1:timer value: 6
(1s)
PRO1:timer value: 7
(1s)
PRO1:timer value: 8
(1s)
PRO1:timer value: 9
(1s)
PRO1:timer value: 10

However, it turns out to print 10 numbers in batch after 10 second

(10s)
PRO1:timer value: 1
PRO1:timer value: 2
PRO1:timer value: 3
PRO1:timer value: 4
PRO1:timer value: 5
PRO1:timer value: 6
PRO1:timer value: 7
PRO1:timer value: 8
PRO1:timer value: 9
PRO1:timer value: 10

Can someone help me figure out what is the root of this mismatch

>Solution :

The problem is with your python script. When running in a pipe line, it doesn’t flush each line. Only when the script finishes, all the output is flushed. Try adding sys.stdout.flush() after the print command.

I suspect you’ll see the same effect when you pipe the output of your python command through type (at least I did when I tested on linux with cat; I don’t use windows).

Leave a ReplyCancel reply