Version 3 of Execute in Parallel and Wait

Updated 2014-03-10 09:18:48 by PeterLewerin

Execute in Parallel and Wait

fileevent is often recommended for execution of multiple processes in parallel, but it requires a script to be written in an event-driven style. Sometimes what is wanted is to execute multiple processes which run in parallel, and wait for them all to complete. Here is an example of that:

#! /bin/env tclsh

proc main {} {
    for {set i 0} {$i < 5} {incr i} {
        set script {
            #simulate a hard-working process
            for {set i 0} {$i < 10000000} {incr i} {
            }
            puts [list hello from [pid]]
        }
        set chan [open |[list [info nameofexecutable] <<$script 2>@stderr]] 
        dict set res $chan command $script
        fconfigure $chan -blocking 0
        lappend background $chan
    }
    while 1 {
        foreach chan $background {
            if {[eof $chan]} {
                if {[set idx [lsearch -exact $background $chan]] >= 0} {
                    set background [lreplace $background $idx $idx]
                }
                catch [close $chan] cres copts
                dict set res $chan result $cres
                dict set res $chan options $copts
            } else {
                puts -nonewline [read $chan]
            }
        }
        if {[llength $background] == 0} {
            break
        }
        after 100
    }
    return $res
}

#puts [main]
main

In contrast with some other solutions, TclX's wait, this example does not require any extension, and should work on various platforms.

Windows users, who typically start a script by double-clicking on the icon, running it in wish, should note that spawning the scripts might be problematic, for reasons discussed under the heading "Windows Console" on the exec page. Two possible solutions are

  • Run the program in tclsh rather than a GUI-based shell
  • Remove the 2>@stderr argument from the list creating the argument to the open command