跑步表现

Consider the following benchmark:

package main

import (
    "io/ioutil"
    "os"
    "os/exec"
    "testing"
)

func BenchmarkRun(b *testing.B) {
    for i := 0; i < b.N; i++ {
        source := `package main

import "fmt"

func main() {
    fmt.Println("foo")
}`
        if err := ioutil.WriteFile("cmd.go", []byte(source), 0777); err != nil {
            b.Error(err)
        }
        defer os.Remove("cmd.go")

        if err := exec.Command("go", "run", "cmd.go").Run(); err != nil {
            b.Error(err)
        }
    }
}

This takes around 0.3sec per operation.

Is there any way of speeding up a compile / run cycle?

It seems clumsy to write a temporary file and exec go run. Is there a way to invoke the compiler without doing this?

You can always create a binary and use it later on. Example:

package main

import (
        "io/ioutil"
        "os"
        "os/exec"
        "path"
        "testing"
)

func BenchmarkRun(b *testing.B) {
        tmpdir, err := ioutil.TempDir("", "go-bench-")
        if err != nil {
                b.Fatal(err)
        }
        defer os.RemoveAll(tmpdir)

        source := `package main

import "fmt"

func main() {
    fmt.Println("foo")
}`
        if err := ioutil.WriteFile(path.Join(tmpdir, "cmd.go"), []byte(source), 0777); err != nil {
                b.Fatal(err)
        }
        defer os.Remove(path.Join(tmpdir, "cmd.go"))

        cmd := exec.Command("go", "build", "-o", "cmd", ".")
        cmd.Dir = tmpdir
        if err := cmd.Run(); err != nil {
                b.Fatal(err)
        }
        defer os.Remove(path.Join(tmpdir, "cmd"))

        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                if err := exec.Command(path.Join(tmpdir, "cmd")).Run(); err != nil {
                        b.Error(err)
                }
        }
}