I recently started playing with the computer science puzzles on codeforces.com (my contest history, rather short at this point). I started this for two reasons:
package main
import “fmt”
func main() {
n := readInt()
sum := 0
for i := 0; i < n; i++ {
sum += readInt()
}
fmt.Println(sum)
}
func readInt() int {
var n int
fmt.Scan(&n)
return n
}
Given a input file with literal 200000 followed by 200000 random integers (about 3MB):
$ time ./nobuf < numbers > /dev/null real 0m4.406s user 0m1.450s sys 0m2.912s
Whoa! 4.5 seconds to read 200000 integers and sum them? How about C++11? Here’s what I thought was an equivalent program in C++:
#include
using namespace std;
int main() {
int n, sum = 0, amt;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> amt;
sum += amt;
}
cout << sum << endl;
}
And the result…
$ time ./sum-c++ < numbers > /dev/null real 0m0.006s user 0m0.002s sys 0m0.002s
6ms seems right to me… what on earth is happening here?! A bit of research (after the contest) and I ran across a thread lamenting the same problem. It turns out that by default, Go uses unbuffered I/O. Ok, fine, let’s switch to buffered I/O:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func solve() {
n := readInt()
sum := 0
for i := 0; i < n; i++ {
sum += readInt()
}
fmt.Println(sum)
}
var scanner *bufio.Scanner
func main() {
scanner = bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
solve()
}
func readString() string {
scanner.Scan()
return scanner.Text()
}
func readInt() int {
val, _ := strconv.Atoi(readString())
return val
}
And results:
$ time ./gobufs < numbers > /dev/null real 0m0.059s user 0m0.047s sys 0m0.010s
That’s 2 orders of magnitude better, but still an order slower than C++11 (0.059s vs 0.006ms). What’s going on here is that we’re building a scanner object which will scan standard input and break it into words. Unlike the defaults, this scanner will buffer input from standard input.
There’s probably a way to make it faster, but at least for the next contest, I will hopefully experience fewer TIME_LENGTH_EXCEEDED errors because of unbuffered reads of the input!