Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TCL make use of pipe and fileevent to maintain subprocess

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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).

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading