i have written following function executing snt2cooc
command (one of preprocessing steps running giza++. our purposes think can consider snt2cooc
script black box):
func snttocooc(srcvocab, tgtvocab, sntpath, outpath string) error { // open out file writing outfile, err := os.create(outpath) if err != nil { return err } defer outfile.close() cmdstr := "snt2cooc" args := []string{srcvocab, tgtvocab, sntpath} cmd := exec.command(cmdstr, args...) cmd.stdout = outfile if err = cmd.run(); err != nil { return err } cmd.wait() return err }
when running, function executes without error, output file empty. same code works other similar commands, not specific snt2cooc
command, , noticed when run command in shell directly:
snt2cooc file1.vcb file2.vcb file3.snt
i following output:
end. 0 2 0 3 0 4 0 5 0 6
(truncated brevity)
and if send output of command file directly shell:
snt2cooc file1.vcb file2.vcb file3.snt > out.txt
the contents of out.txt
expected:
0 2 0 3 0 4 0 5 0 6
notice how in first case, line end.
output stdout first, , real output of command sent stdout. therefore think there race condition going on, go code finishes executing before command's final output written file. despite calling cmd.wait()
. i'm not sure snt2cooc
command doing internally. provide hint on how solve this?
edit 1:
it seems following code, sleep of 500ms included, consistently writes output file snt2cooc
command:
cmdstr := "snt2cooc" args := []string{srcvocab, tgtvocab, sntpath} cmd := exec.command(cmdstr, args...) stdout, err := cmd.stdoutpipe() time.sleep(500 * time.millisecond) if err != nil { return err } err = cmd.start() if err != nil { return err } out := bufio.newscanner(stdout) out.scan() { outfile.write(out.bytes()) outfile.writestring("\n") } if err := out.err(); err != nil { return err }
this proves me there race condition going on, go program exiting before output written file. added bounty question, hope can 1) explain why happening , 2) provide non-hacky way (i.e. 500ms sleep) fix it.
first, clean code.
cmd.stderr = os.devnull
, ignore stderr. stdout , stderr specify process's standard output , error. if either nil, run connects corresponding file descriptor null device (os.devnull).
cmd.wait()
returns error,
ignore it. func (c *cmd) wait() error
.
wait
waits command exit. must have been started start.
use run,
not start.
what output when run code?
failure.go
:
package main import ( "fmt" "os" "os/exec" ) func main() { err := snttocooc("file1.vcb", "file2.vcb", "file3.snt", "out.txt") if err != nil { fmt.println(err) } } func snttocooc(srcvocab, tgtvocab, sntpath, outpath string) error { outfile, err := os.create(outpath) if err != nil { return err } defer outfile.close() cmdstr := "snt2cooc" args := []string{srcvocab, tgtvocab, sntpath} cmd := exec.command(cmdstr, args...) cmd.stdout = outfile cmd.stderr = os.stderr err = cmd.run() if err != nil { return err } return err }
run:
$ rm -f out.txt && go run failure.go && cat out.txt
also, output when run code cmd.stdout = os.stdout
substituting cmd.stdout = outfile
.
Comments
Post a Comment