设为首页 加入收藏

TOP

Go指南 - 笔记(四)
2019-03-26 16:13:28 】 浏览:308
Tags:指南 笔记
, 0, 200, 200) } func (i Image) At(x, y int) color.Color { return color.RGBA{uint8(x), uint8(y), uint8(255), uint8(255)} } func main() { m := Image{} pic.ShowImage(m) }

五、并发

1.Go程

Go程(goroutine)是由Go运行时管理的轻量级线程。

go f()

2.信道

信道是带有类型的管道,你可以通过它用信道操作符<-来发送或者接收值。

ch <- v // 将v发送至信道ch
v := <-ch // 从ch接收值并赋予v

和映射与切片一样,信道在使用前必须创建:

ch := make(chan int)
package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // 将和送入c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}
    
    c := make(chan int)
    go sum(s[:len(s) / 2], c)
    go sum(s[len(s) / 2:], c)
    x, y := <-c , <-c // 从c中接收
    
    fmt.Println(x, y)
    // -5
    // 17
}

信道可以是带缓冲的。将缓冲长度作为第二个参数提供给make来初始化一个带缓冲的信道。

ch := make(chan int, 100)

3.range和close

发送者可通过close关闭一个信道来表示没有需要发送的值了。

接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭;若没有值可以接收且信道已被关闭,那么在执行完

v, ok := <-ch

之后ok会被设置为false

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

只有发送者才能关闭信道。向一个已经关闭的信道发送数据会引发程序恐慌(panic)。
信道与文件不同,通常情况下无需关闭它们。只有在必须告诉接收者不再有需要发送的值时才有必要关闭,例如终止一个range循环。

通过信道实现斐波那契数列:

package main

import "fmt"

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)
    }
}

4.select语句

select语句使一个Go程可以等待多个通信操作。
select会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。

package main

import "fmt"

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中接收会阻塞时执行
}
package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(1000 * time.Millisecond)
    boom := time.After(5000 * time.Millisecond)
    for {
        select {
            case <-tick:
                fmt.Println("tick")
            case <-boom:
                fmt.Println("BOOM!")
                return
            default:
                fmt.Println("     .")
                time.Sleep(500 * time.Millisecond)
        }
    }
}

The end. Last updated by Jehorn, 3:30 PM, Tuesday, March 26, 2019 (GMT+8)

首页 上一页 1 2 3 4 下一页 尾页 4/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Go语言数组和切片的原理 下一篇Go基础(2)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目