猿问

为什么我的 Go 程序在以下场景中的表现比预期的要差得多?

我正在用 C、Go 和 Python 解决一个简单的问题并比较结果。该解决方案只是应该在if-else块内有两个方程。以下是我的解决方案的代码:

C

Python

GO

我比较了这三种语言处理浮点结果的方式,因此制作了这个脚本来生成测试用例,然后比较结果,一次两个。

奇怪的是运行前 3 个脚本所需的时间。C 程序显然在几秒钟内运行。Python 大约需要 2.5-3 秒。但是,Go 需要大约 24-25 秒才能在generate_test_cases.py脚本生成的测试用例上运行程序。

我认为就运行时间而言,Go 会介于 C 和 Python 之间。我是否在用 Go 代码做一些低效的事情,如果是,那是什么?

PS我也运行了上面三个程序,没有文件处理操作,结果还是一样,即Go比其他两个花费了非常长的时间。


胡说叔叔
浏览 177回答 2
2回答

四季花海

和 Max 一样,我强烈怀疑 Go 的缓慢与糟糕的 I/O 性能有关。我测试了这个假设:package mainimport "fmt"import "os"import "time"func main(){&nbsp; &nbsp; now := time.Now()&nbsp; &nbsp; input,_ := os.Open("testing/test_cases.txt")&nbsp; &nbsp; defer input.Close()&nbsp; &nbsp; output,_ := os.Create("testing/Goutput.txt")&nbsp; &nbsp; defer output.Close()&nbsp; &nbsp; var ncases int&nbsp; &nbsp; var p float64&nbsp; &nbsp; fmt.Fscanf(input,"%d",&ncases)&nbsp; &nbsp; fmt.Println("Opened files in ", time.Since(now), "seconds")&nbsp; &nbsp; now = time.Now()&nbsp; &nbsp; cases := make([]float64, ncases)&nbsp; &nbsp; fmt.Println("Made array in ", time.Since(now), "seconds")&nbsp; &nbsp; now = time.Now()&nbsp; &nbsp; for i := 0; i < ncases; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fscanf(input,"%f",&cases[i])&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("Read data in ", time.Since(now), "seconds")&nbsp; &nbsp; now = time.Now()&nbsp; &nbsp; for i := 0; i < ncases; i++ {&nbsp; &nbsp; &nbsp; &nbsp; p = cases[i]&nbsp; &nbsp; &nbsp; &nbsp; if p >= 0.5 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cases[i] = 10000 * (1-p) * (2*p-1) + 10000&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cases[i] = p*(1-2*p)*10000 + 10000&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("Processed data in ", time.Since(now), "seconds")&nbsp; &nbsp; now = time.Now()&nbsp; &nbsp; for i := 0; i < ncases; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintln(output, cases[i])&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("Output processed data in ", time.Since(now), "seconds")}运行它产生了这个输出:在 2.011228ms 秒内打开文件在 109.904us 秒内制作阵列4.524544608s秒读取数据10.083329ms 秒内处理的数据1.703542918s秒输出处理数据所以看起来在我的机器上,所有的数学运算都发生在大约 10 毫秒内,但 I/O 很慢,证实了假设。正如 Janne 在评论中指出的那样,可能有比fmt.更新:例如,包装input和outputwithbufio的读者和作家:binput := bufio.NewReader(input)boutput := bufio.NewWriter(output)使用binput和boutput缓冲 I/O,您的原始版本在我的机器上运行时间为 2.1 秒,比 Python 的 2.7 快一些。更新 2:我注意到通过切换到缓冲 I/O 会得到不同的结果。事实证明,您还需要调整格式字符串以包含\n,就像您在 C 版本中所做的那样。我认为这实际上更正确,但看起来你可以在没有缓冲的情况下逃脱。这对Flush()你的缓冲输出也很重要,我做了但之前没有提到。这是我完整的缓冲解决方案:package mainimport "fmt"import "os"import "bufio"import "time"func main(){&nbsp; &nbsp; now := time.Now()&nbsp; &nbsp; nbinput, _ := os.Open("testing/test_cases.txt")&nbsp; &nbsp; defer nbinput.Close()&nbsp; &nbsp; nboutput, _ := os.Create("testing/Goutput.txt")&nbsp; &nbsp; defer nboutput.Close()&nbsp; &nbsp; binput := bufio.NewReader(nbinput)&nbsp; &nbsp; boutput := bufio.NewWriter(nboutput)&nbsp; &nbsp; var ncases int&nbsp; &nbsp; var gain, p float64&nbsp; &nbsp; fmt.Fscanf(binput,"%d\n",&ncases)&nbsp; &nbsp; for i := 0; i < ncases; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fscanf(binput, "%f\n", &p)&nbsp; &nbsp; &nbsp; &nbsp; if p >= 0.5 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gain = 10000 * (1-p) * (2*p -1)&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; gain = p*(1-2*p)*10000&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; fmt.Fprintln(boutput, gain+10000)&nbsp; &nbsp; }&nbsp; &nbsp; boutput.Flush()&nbsp; &nbsp; fmt.Println("Took ", time.Since(now), "seconds")}

暮色呼如

我想以下几行在 go 中工作得更慢。&nbsp;&nbsp;&nbsp;&nbsp;fmt.Fscanf(input,"%f",&p)&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;fmt.Fprintln(output,gain+10000)当你做 IO 时,Go 的魔法就会发生。它们看起来是同步的,但实际上它们是异步的。Go rotine 执行异步请求并将控制权返回给调度程序。调度程序寻找另一个等待控制的 goroutine,但只有一个等待 io。所以调度器循环什么都不做。如果您有 2、10 或 100 个并发 goroutine,那么性能会更好。
随时随地看视频慕课网APP

相关分类

Go
我要回答