为了提高效率,有时需要两个函数一起运行。
f() // 程序会等到 f() 执行完才会执行下一步
go f() // 创建一个 goroutine 来调用 f() ,程序不等待,直接执行下一步
1. 下述代码中主函数中的 goroutine 计算了第45个斐波那契数
package mainimport ("fmt""time"
)func main() {go spinner(100 * time.Millisecond)const n = 45fibN := fib(n)fmt.Printf("\rFibonacci(%d) = %d\n", n, fibN)
}func spinner(delay time.Duration) {for {for _, r := range `-\|/` {fmt.Printf("\r%c", r)time.Sleep(delay)}}
}func fib(x int) int {if x < 2 {return x}return fib(x-1) + fib(x-2)
}
输出结果
Fibonacci(45) = 1134903170
2. 启动一个 tcp 服务器,用 goroutine 每隔一秒返回一个时间
package mainimport ("io""log""net""time"
)func main() {listener, err := net.Listen("tcp", "localhost:8000")if err != nil {log.Fatal(err)}for {conn, err := listener.Accept()if err != nil {log.Print(err)continue}go handleConn(conn)}
}func handleConn(c net.Conn) {defer c.Close()for {_, err := io.WriteString(c, time.Now().Format("2006-01-02 15:04:05\n"))if err != nil {return}time.Sleep(1 * time.Second)}
}
还需要一个配套的客户端来访问上面的 tcp 服务
package mainimport ("io""log""net""os"
)func main() {conn, err := net.Dial("tcp", "localhost:8000")if err != nil {log.Fatal(err)}defer conn.Close()mustCopy(os.Stdout, conn)
}func mustCopy(dst io.Writer, src io.Reader) {if _, err := io.Copy(dst, src); err != nil {log.Fatal(err)}
}
输出示例
2024-01-20 00:33:15
2024-01-20 00:33:16
2024-01-20 00:33:17
2024-01-20 00:33:18
2024/01/20 00:33:19
3. goroutine 结合 channel 计算文件夹的体积
package mainimport ("flag""fmt""os"
)func main() {flag.Parse()roots := flag.Args()if len(roots) == 0 {roots = []string{"."} // 默认当前目录}fileSizes := make(chan int64)go func() {for _, root := range roots {walkDir(root, fileSizes)}close(fileSizes)}()var nFiles, nBytes int64for size := range fileSizes {nFiles++nBytes += size}printDiskUsage(nFiles, nBytes)
}func printDiskUsage(nFiles, nBytes int64) {fmt.Printf("%d files %.1f GB (%1.f MB)\n", nFiles, float64(nBytes)/1e9, float64(nBytes)/1e6)
}func walkDir(dir string, fileSizes chan<- int64) {for _, entry := range dirEntries(dir) {if entry.IsDir() {// subdir := filepath.Join(dir, entry.Name())// walkDir(subdir, fileSizes)} else {fileInfo, err := entry.Info()if err != nil {fmt.Fprintf(os.Stderr, "du1: %v\n", err)} else {fileSizes <- fileInfo.Size()}}}
}func dirEntries(dir string) []os.DirEntry {entries, err := os.ReadDir(dir)if err != nil {fmt.Fprintf(os.Stderr, "du1: %v\n", err)return nil}return entries
}
输出
53 files 9.8 GB (9795 MB)