[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