聽說google出品的go語言也是系統開發中常用的,性能到底怎么樣,還是老辦法,讓DeepSeek寫個程序跑一下,基于以往的經驗,直接讓它同時編寫有緩沖和無緩沖版本。
package mainimport ("bufio""fmt""os""sort""time"
)// 無緩沖版本
func unbufferedSort(filename string) error {lines, err := readLines(filename)if err != nil {return err}sort.Strings(lines) // Go標準庫的優化排序for _, line := range lines {fmt.Println(line) // 無緩沖直接輸出}return nil
}// 帶緩沖版本 (默認4MB緩沖區)
func bufferedSort(filename string, bufferSize int) error {lines, err := readLines(filename)if err != nil {return err}sort.Strings(lines)// 創建緩沖寫入器writer := bufio.NewWriterSize(os.Stdout, bufferSize)defer writer.Flush()for _, line := range lines {_, err := writer.WriteString(line + "\n")if err != nil {return err}}return nil
}// 通用文件讀取函數
func readLines(filename string) ([]string, error) {file, err := os.Open(filename)if err != nil {return nil, err}defer file.Close()var lines []stringscanner := bufio.NewScanner(file)for scanner.Scan() {lines = append(lines, scanner.Text())}return lines, scanner.Err()
}func main() {if len(os.Args) < 3 {fmt.Println("Usage:")fmt.Println(" sort_lines <filename> <mode> [bufferSize]")fmt.Println("Modes: unbuffered, buffered")os.Exit(1)}filename := os.Args[1]mode := os.Args[2]start := time.Now()var err errorswitch mode {case "unbuffered":err = unbufferedSort(filename)case "buffered":bufferSize := 4 * 1024 * 1024 // 默認4MBif len(os.Args) > 3 {_, err = fmt.Sscanf(os.Args[3], "%d", &bufferSize)if err != nil {fmt.Printf("Invalid buffer size: %v\n", err)os.Exit(1)}}err = bufferedSort(filename, bufferSize)default:fmt.Println("Invalid mode")os.Exit(1)}if err != nil {fmt.Printf("Error: %v\n", err)os.Exit(1)}elapsed := time.Since(start)fmt.Fprintf(os.Stderr, "Processing time: %s\n", elapsed)
}
編譯執行
go/bin/go build -o gosort sort_lines.go
time ./gosort varchar.txt buffered > /dev/null
Processing time: 3.497140997sreal 0m3.554s
user 0m0.621s
sys 0m0.366s
time ./gosort varchar.txt unbuffered > /dev/null
Processing time: 3.720407838sreal 0m4.603s
user 0m0.755s
sys 0m0.474s
time ./gosort varchar.txt buffered > vcc.txt
Processing time: 3.798995799sreal 0m3.855s
user 0m0.681s
sys 0m0.301stime ./gosort varchar.txt buffered 65536 > vcc.txt
Processing time: 3.891683917sreal 0m3.959s
user 0m0.627s
sys 0m0.380stime ./gosort varchar.txt unbuffered > vcc.txt
^Creal 1m26.182s
user 0m3.305s
sys 0m7.983s
nm -D gosort >go.h
nm: gosort: no symbols
nm gosort >go.h
如上所示,帶緩沖的版本性能尚可,緩沖區大小影響不大。無緩沖版本只能用離奇來表示,而且go語言默認編譯就是優化,也沒啥可以調優的。
與Zig語言一樣,編譯出的是靜態版本,看不出調用了哪些系統庫函數。
后記
張澤鵬先生提醒我是否在WSL上測試,根據以往的經驗WSL的讀寫性能比較糟糕
我改用windows版本編譯運行,比較正常
C:\d>gosort varchar.txt buffered > vcc.txt
Processing time: 600.3093msC:\d>gosort varchar.txt unbuffered > vcc.txt
Processing time: 2.4327929s
張先生也寫了一版,效率比deepseek的還高一些。他采用了64K讀取緩沖區和ReadString,而deepseek使用了NewScanner。
package mainimport ("bufio""fmt""io""os""slices"
)func main() {if len(os.Args) != 2 {fmt.Fprintf(os.Stderr, "Usage: %s <filename>\n", os.Args[0])os.Exit(1)}file, err := os.Open(os.Args[1])if err != nil {fmt.Fprintf(os.Stderr, "failed to open file: %w", err)os.Exit(1)}defer file.Close()lines := make([]string, 0, 1024)// 讀取reader := bufio.NewReaderSize(file, 64*1024)for {line, err := reader.ReadString('\n')if err == io.EOF {if len(line) > 0 {// 最后一行有內容但沒有換行符;添加內容和換行符lines = append(lines, line + "\n")}break} else if err != nil { // 其他錯誤fmt.Fprintf(os.Stderr, "failed to read line: %w", err)os.Exit(1)os.Exit(1)} else {lines = append(lines, line)}}// 排序slices.Sort(lines)// 輸出writer := bufio.NewWriterSize(os.Stdout, 64*1024)defer writer.Flush()for _, line := range lines {if _, err := writer.WriteString(line); err != nil {fmt.Fprintf(os.Stderr, "failed to write line: %w", err)os.Exit(1)}}
}
在Kylinx上運行的結果如下
:/shujv/par$ time ./zhanggosort varchar.txt > /dev/nullreal 0m0.875s
user 0m0.792s
sys 0m0.156s
:/shujv/par$ time ./zhanggosort varchar.txt > vcc.txtreal 0m0.874s
user 0m0.768s
sys 0m0.052s
:/shujv/par$ time ./gosort varchar.txt buffered > vcc.txt
Processing time: 1.14983689sreal 0m1.187s
user 0m1.132s
sys 0m0.264s
go的一個好處是不挑glibc版本,kylinx直接跑