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)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度