exec.Command().Run() fails in goroutine?

Hello. My very first post here, so hi all! I am also new to Go, so please excuse my basic questions.

I am trying to run (just to check how it works) a Python script from go using exec.Command().Run(). It works fine in a regular way, as below. The Python script is as follows:

import time

if __name__ == '__main__':
    time.sleep(3)
    print("Python job finished")

and I run it from the following Go program:

package main

import (
	"fmt"
	"os"
	"os/exec"
)

func RunPython(path string) {
	cmd := exec.Command("python3", path)
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Error when running Python job: %s", err)
	}
}

func main() {
	RunPython("job.py")
}

This runs fine, which I see by the time delay (I checked also in other ways, though). However, when I change the main function to use a goroutine:

func main() {
	go RunPython("job.py")
}

it simply does not run (no delay, and whatever is in the Python script is not executed), though it does not throw any error.

What? Why?

Your main goroutine starts the other goroutine and then exits successfully, before the other goroutine has any chance to even set up the CMD.

You need to “sync” between both goroutines.

1 Like

Thanks a lot!

Yup, now I see that I have to take care of not finishing the main goroutine before the others. Enough to add time.Sleep() to the main goroutine:

func main() {
	go RunPython("job.py")
	time.Sleep(10 * time.Second)
}

This was enough for Python’s job to finish. I know this is not the best way to synchronize routines, but it helped me understand this simple thing. Thank you!

OK, I now know how to synchronize the goroutines:

package main

import (
	"fmt"
	"os/exec"
	"sync"
)

func RunPython(path string, wg *sync.WaitGroup) {
	defer wg.Done()
	cmd := exec.Command("python3", path)
	err := cmd.Run()
	if err != nil {
		fmt.Printf("Error when running Python job: %s", err)
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	go RunPython("job.py", &wg)
	wg.Wait()
}

And this seems to work just fine and dandy.