FizzBuzz seems slow: why?

[ANSWER] Go does not buffer stdout. Switching to the buffered version and manual cleaning brings it closer to what you expect. Avoiding fmt makes it work as fast as you like.

I am trying to write a 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 only one second to complete. When I write an equivalent program in C, Rust, Haskell or Python, it takes from one and a half seconds (Python) to zero seconds (Rust and Haskell).

Is this expected, or am I missing some go-fu? Why does the move look slower than other languages?

[EDIT]

Work with the profiler, as suggested by Robert Harvey.

It seems like 100% of the time is spent on fmt. (* fmt) .fmt_complex, which I assume is associated with Println (?). I also tried the program with strconv.Itoa instead of fmt.Sprint, and I got a slight performance increase (~ 0.2s), but the same basic results.

This is a slow print, and if so, why?

[EDIT]

For jgritty, the equivalent Python program and timings. I am wondering why printing is slower? Am I doing something backstage that I don’t know about?

 $ 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 
+7
performance go fizzbuzz
source share
1 answer

Standard output is buffered in Python and C, but not Go. Buffer output to compare apples and apples. It 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 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("\n") } 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) } } 
+7
source share

All Articles