以下说明的时间,均是在本人的电脑上测得的,不同电脑上很有可能不同,所以请只参考时间之间的相对值而非绝对值。
用go语言来从标准输入stdin和标准输出stdout来读写数据的时候,也许大家都习惯使用fmt包下的函数,比如fmt.Scanf和fmt.Println,不过实际上Scanf是相当慢的。我在我的电脑上试验,在命令行上将输入重定向到一个有1e6个整数的文件上时,使用fmt.Scanf居然用了接近20秒,慢得令人发指,要知道Java的Scanner类已经是众所周知的慢了,不过即使是用Java来写,用Scanner类来获得输入,在我的机器上完成同样的工作也“只”需要2s左右的时间(所以使用Java时如果想输入得更快,最好使用BufferedReader类和StringTokenizer类,如果想了解具体使用可以自行搜索),更别提c语言的scanf函数,只需要短短0.2s左右。
同样地,fmt.Print系列函数也慢得吓人,我将0到999999这1e6个数字通过重定向输出到一个文件上在我的电脑上也用时接近20s,相比之下使用c语言的printf函数,完成同样的事情,只需要0.2s多一点点。
所以在需要从标准输入输出大量地读写时,直接使用fmt包的Print和Scan系列函数实在不是个好主意。
好在除了使用其他语言之外并不是没有好的替代方案,那就是使用bufio包,下面举例说明其用法。
首先是从stdout输出:
package main

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

func main() {
    out := bufio.NewWriter(os.Stdout)
    defer out.Flush()
    for i := 0; i < 1000000; i++ {
        fmt.Fprintln(out, i)
    }
    // 以上3行只是为了演示如何具体输出而已
}
完成之前描述的输出工作,大约只需要0.4s。

然后是从标准输入中读取整数(如果需要读字符串,在创建in变量后,简单地使用in的ReadString或者ReadSlice方法即可):
package main

import (
    "os"
    "bufio"
)

func main() {
    for x := 0; readInt(&x) == nil; {
        // do work with x
    }
}

var in = bufio.NewReader(os.Stdin)
func readInt(out *int) error {
    var ans, sign int = 0, 1
    var readed = false
    c, err := in.ReadByte()
    for ; err == nil && (c < '0' || '9' < c); c, err = in.ReadByte() {
        if c == '-' { sign = -sign}
    }
    for ; err == nil && '0' <= c && c <= '9'; c, err = in.ReadByte() {
        ans = ans << 3 + ans << 1 + int(c - '0')
        readed = true
    }
    if readed {
        *out = ans * sign
        return nil
    }
    return err
}
在我的机器上用这种方式来读取输入甚至比c的scanf函数还快,我相信在大多数机器上它应该也是很快的。
以上。