doucuoyan0426 2014-10-01 20:22
浏览 40
已采纳

FizzBu​​zz程序似乎很慢:为什么?

[ANSWER] Go doesn't buffer stdout. Switching to a buffered version and manually flushing brings it much closer to what you would expect. Avoiding fmt makes it run as fast as you like.

I'm trying to write the FizzBuzz program in Go.

func main() {
  for i := 1; i <= 1000000; i++ {
    fmt.Println(fizzbuzz(i))
  }
}

func fizzbuzz(n int) string {
  fizzy := n%3 == 0
  buzzy := n%5 == 0

  switch {
  case fizzy && buzzy:
    return "FizzBuzz"
  case fizzy:
    return "Fizz"
  case buzzy:
    return "Buzz"
  default:
    return fmt.Sprint(n)
  }
}

When I run it for numbers from 1 to a million it takes just under a second to complete. When I write the equivalent program in C, Rust, Haskell or Python it takes anywhere from half a second (Python) to zero seconds (Rust and Haskell).

Is this to be expected, or am I missing some Go-fu? Why does the go seem slower than the other languages?

[EDIT]

Running with the profiler as suggested by Robert Harvey.

It looks like 100% of the time is spent in fmt.(*fmt).fmt_complex, which I'm guessing is related to the Println(?). Also tried the program with strconv.Itoa instead of the fmt.Sprint and I get the slight performance increase (~0.2s) but the same basic results.

Is it the printing that's slow and if so why?

[EDIT]

For jgritty the equivalent Python program and timings. I'm interested in why the printing is slower? Is go doing something behind the scenes I'm not aware of?

$ cat fizzbuzz.py
def fizzbuzz(n):
    fizzy = n%3 == 0
    buzzy = n%5 == 0

    if fizzy and buzzy:
        return "FizzBuzz"
    elif fizzy:
        return "Fizz"
    elif buzzy:
        return "Buzz"
    else:
        return ("%u" % n)

def main():
    for i in range(1, 10**6):
        print(fizzbuzz(i))

main()
$ time pypy3 fizzbuzz.py >/dev/null

real    0m0.579s
user    0m0.545s
sys     0m0.030s
  • 写回答

1条回答 默认 最新

  • dongshu9458 2014-10-01 20:35
    关注

    The standard output is buffered in Python and C, but not Go. Buffer the output for an apples to apples comparison. This almost cut the time in half on my laptop.

    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main() {
        w := bufio.NewWriter(os.Stdout)
        for i := 1; i <= 1000000; i++ {
             fmt.Fprintln(w, fizzbuzz(i))
        }
        w.Flush()
    }
    

    Eliminate the use of the fmt package for another improvement:

    package main
    
    import (
        "bufio"
        "os"
        "strconv"
    )
    
    func main() {
        w := bufio.NewWriter(os.Stdout)
        for i := 1; i <= 1000000; i++ {
            w.WriteString(fizzbuzz(i))
            w.WriteString("
    ")
        }
        w.Flush()
    }
    
    func fizzbuzz(n int) string {
        fizzy := n%3 == 0
        buzzy := n%5 == 0
    
        switch {
        case fizzy && buzzy:
            return "FizzBuzz"
        case fizzy:
            return "Fizz"
        case buzzy:
            return "Buzz"
        default:
            return strconv.Itoa(n)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器