欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

小试牛刀

程序员文章站 2024-02-23 08:05:22
...

go 使并发编程变得简单

func square() {
    naturals := make(chan int)
    squares := make(chan int)

    // Counter
    go func() {
        for x := 0; x < 10; x++ {
            naturals <- x
        }
        close(naturals)
    }()
    // Squarer
    go func() {
        for {
            x, ok := <-naturals
            if !ok {
                break // channel was closed and drained
            }
            squares <- x * x
        }
        close(squares)
    }()
    // Printer
    for {
        x, ok := <-squares
        if !ok {
            break
        }
        fmt.Println(x)
    }
}

当一个 channel 被 close 后再 send 会 panic, 再取值不会阻塞了而是直接返回 zero value (零值,这里 int 会返回 0)。可通过第二个参数 ok 判断 channel 是否关闭且里面的值已经取净(drained)。

range 可遍历 channel 并在 channel close 且 drained 后结束遍历,所以上面的例子可用 range 简化

func square() {
    naturals := make(chan int)
    squares := make(chan int)

    // Counter
    go func() {
        for x := 0; x < 10; x++ {
            naturals <- x
        }
        close(naturals)
    }()
    // Squarer
    go func() {
        for x := range naturals {
            squares <- x * x
        }
        close(squares)
    }()
    // Printer
    for x := range squares {
        fmt.Println(x)
    }
}

看看 select 用法

package main

import (
    "fmt"
    "os"
    "time"
)

func couter() {
    tick := time.Tick(1 * time.Second)
    abort := make(chan struct{})

    go func() {
        os.Stdin.Read(make([]byte, 1)) // 按enter 键 abort
        abort <- struct{}{}
    }()

    for countdown := 10; countdown > 0; countdown-- {
        select {
        case <-abort:
            fmt.Println("launch aborted")
            return
        case <-tick:
            fmt.Println(countdown)
        }
    }

    fmt.Println("launched")
}