Goroutines 和 Channels

为了提高效率,有时需要两个函数一起运行。

f() // 程序会等到 f() 执行完才会执行下一步
go f() // 创建一个 goroutine 来调用 f() ,程序不等待,直接执行下一步

1. 下述代码中主函数中的 goroutine 计算了第45个斐波那契数

package main

import (
	"fmt"
	"time"
)

func main() {
	go spinner(100 * time.Millisecond)
	const n = 45
	fibN := 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 main

import (
	"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 main

import (
	"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 main

import (
	"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 int64
	for 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)

你可能感兴趣的:(go/golang,进阶教程,go,golang,后端)