美文网首页
【技术】Golang——goroutine、channel

【技术】Golang——goroutine、channel

作者: 念_夕 | 来源:发表于2018-04-19 14:55 被阅读39次

    goroutine

    goroutine 是由 Go 运行时环境管理的轻量级线程。
    go f(x, y, z)
    开启一个新的 goroutine 执行

    f(x, y, z)
    f , x , yz 是当前 goroutine 中定义的,但是在新的 goroutine 中运行 f
    goroutine 在相同的地址空间中运行,因此访问共享内存必须进行同步。sync 提供了这种可能,不过在 Go 中并不经常用到,因为有其他的办法。

    func say(s string) {
        for i := 0; i < 5; i++ {
            fmt.Println(i)
            time.Sleep(100 * time.Millisecond)
            fmt.Println(s)
        }
    }
    
    func main() {
        go say("world")
        say("hello")
    }
    /*
    0
    0
    world
    1
    hello
    1
    world
    2
    hello
    2
    world
    3
    hello
    3
    world
    4
    hello
    4
    world
    hello
    */
    /*
    注释 fmt.Println(i)后结果
    world
    hello
    world
    hello
    hello
    world
    hello
    world
    hello
    world
    */
    // 结论:在不同线程,顺序随机
    

    channel

    channel 是有类型的管道,可以用 channel 操作符 <- 对其发送或者接收值。

    ch <- v    // 将 v 送入 channel ch。
    v := <-ch  // 从 ch 接收,并且赋值给 v。
    (“箭头”就是数据流的方向。)
    

    和 map 与 slice 一样,channel 使用前必须创建:
    ch := make(chan int)
    默认情况下,在另一端准备好之前,发送和接收都会阻塞。这使得 goroutine 可以在没有明确的锁或竞态变量的情况下进行同步。

    func sum(a []int, c chan int) {
        sum := 0
        for _, v := range a {
            sum += v
        }
        c <- sum // 将和送入 c
    }
    
    func main() {
        a := []int{7, 2, 8, -9, 4, 0}
    
        c := make(chan int)
        go sum(a[:len(a)/2], c) // 17
    
        go sum(a[len(a)/2:], c) // -5
    
        go sum(a[2:len(a)-1], c) // 3
        x, y, z := <-c, <-c, <-c// 从 c 中获取
    
        fmt.Println(x, y, z, x+y+z)
        // 3 -5 17 15
    }
    

    缓冲 channel
    channel 可以是 带缓冲的。为 make 提供第二个参数作为缓冲长度来初始化一个缓冲 channel:
    ch := make(chan int, 100)
    向缓冲 channel 发送数据的时候,只有在缓冲区满的时候才会阻塞。当缓冲区清空的时候接受阻塞

    range 和 close

    发送者可以 close 一个 channel 来表示再没有值会被发送了。接收者可以通过赋值语句的第二参数来测试 channel 是否被关闭:当没有值可以接收并且 channel 已经被关闭,那么经过

    v, ok := <-ch
    之后 ok 会被设置为 false

    循环 for i := range c 会不断从 channel 接收值,直到它被关闭。

    注意: 只有发送者才能关闭 channel,而不是接收者。向一个已经关闭的 channel 发送数据会引起 panic。 还要注意: channel 与文件不同;通常情况下无需关闭它们。只有在需要告诉接收者没有更多的数据的时候才有必要进行关闭,例如中断一个 range

    func fibonacci(n int, c chan int) {
        x, y := 0, 1
        for i := 0; i < n; i++ {
            c <- x
            x, y = y, x+y
        }
        close(c)
    }
    
    func main() {
        c := make(chan int, 10)
        go fibonacci(cap(c), c)
        for i := range c {
            fmt.Println(i)
        }
    }
    /*
    0
    1
    1
    2
    3
    5
    8
    13
    21
    34
    */
    

    select

    select 语句使得一个 goroutine 在多个通讯操作上等待。
    select 会阻塞,直到条件分支中的某个可以继续执行,这时就会执行那个条件分支。当多个都准备好的时候,会随机选择一个。

    func fibonacci(c, quit chan int) {
        x, y := 0, 1
        for {
            select {
            case c <- x:
                x, y = y, x+y
            case <-quit:
                fmt.Println("quit")
                return
            }
        }
    }
    
    func main() {
        c := make(chan int)
        quit := make(chan int)
        go func() {
            for i := 0; i < 10; i++ {
                fmt.Println(<-c)
            }
            quit <- 0
        }()
        fibonacci(c, quit)
    }
    /*
    0
    1
    1
    2
    3
    5
    8
    13
    21
    34
    quit
    */
    

    默认选择
    当 select 中的其他条件分支都没有准备好的时候,default 分支会被执行。
    为了非阻塞的发送或者接收,可使用 default 分支:

    select {
    case i := <-c:
        // 使用 i
    default:
        // 从 c 读取会阻塞
    }
    
    func main() {
        tick := time.Tick(100 * time.Millisecond)
        boom := time.After(500 * time.Millisecond)
        for {
            select {
            case <-tick:
                fmt.Println("tick.")
            case <-boom:
                fmt.Println("BOOM!")
                return
            default:
                fmt.Println("    .")
                time.Sleep(50 * time.Millisecond)
            }
        }
    }
    /*
        .
        .
    tick.
        .
        .
    tick.
        .
        .
    tick.
        .
        .
    tick.
        .
        .
    BOOM!
    */
    

    相关文章

      网友评论

          本文标题:【技术】Golang——goroutine、channel

          本文链接:https://www.haomeiwen.com/subject/incwkftx.html