2014-10-01 3 views
7

[ANSWER] Go가 표준 버퍼를 버퍼링하지 않습니다. 버퍼링 된 버전으로 전환하고 수동으로 플러시하면 예상했던 것과 훨씬 더 가까워집니다. fmt를 피하면 원하는만큼 빠르게 실행할 수 있습니다.FizzBuzz 프로그램이 느린 것 같습니다. 이유가 무엇입니까?

나는 Go에 FizzBuzz 프로그램을 작성하려고합니다.

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) 
    } 
} 

1에서 100 만까지 숫자로 실행하면 완료하는 데 몇 초가 걸립니다. C, Rust, Haskell 또는 Python으로 동등한 프로그램을 작성할 때 0.5 초 (파이썬)에서 0 초 (Rust와 Haskell)까지 걸립니다.

예상 되나요, 아니면 Go-fu가 누락 되었습니까? 왜 다른 언어보다 이동 속도가 느린 것 같습니까?

[편집]

로버트 하비 (Robert Harvey)가 제안한 프로파일 러에서 실행.

fmt. (* fmt) .fmt_complex에 100 % 시간이 소요 된 것 같습니다. 필자는 Println (?)과 관련 있다고 추측합니다. 또한 fmt.Sprint 대신 strconv.Itoa를 사용하여 프로그램을 시험해 보았는데 약간의 성능 향상 (~ 0.2s)을 얻었지만 동일한 기본 결과를 얻었습니다.

인쇄 속도가 느린 이유는 무엇입니까? jgritty 등가 파이썬 프로그램 용 타이밍

[EDIT]

. 인쇄 속도가 느린 이유는 무엇입니까? 내가 알지 못하는 무대 뒤에서 뭔가하고 있는거야?

$ 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 
+0

http://blog.golang.org/profiling-go-programs 하스켈 게으른 언어이다 –

+0

참고; 실제로 출력물을 요구할 때까지는 결과를 평가하지 않을 것입니다. Rust의 경우도 마찬가지입니다. –

+0

다른 언어보다 시작하는 데 시간이 오래 걸릴 수 있습니까? 프로그램이 더 많은 데이터를 처리하도록하면 약 10 초가 걸립니다. –

답변

7

표준 출력은 Python 및 C에서는 버퍼링되지만 Go는 버퍼링되지 않습니다. 사과 대 사과 비교 결과를 버퍼링합니다. 이것은 거의 내 노트북에서 절반으로 시간을 삭감.

import (
    "bufio" 
    "fmt" 
    "os" 
) 

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

또 다른 개선을위한 fmt package의 사용을 제거 :

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) 
    } 
} 
+0

나는 Println 대신 fmt.Fprintln을 사용한다고 가정합니다. – Joseph

+0

그것은 저에게 다량 성과 개선을 얻는 것을 보인다! 4 배는 빨라졌고, 1 초에 1/4 정도 줄어 들었습니다. – Joseph

+2

Go가 기본적으로 stdout을 버퍼링하지 않기로 결정한 점에 흥미가 있습니다. 이유는 무엇입니까? – Joseph

관련 문제