goroutine and channel 2020-07-20

9_SooHyun · · 506 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

参考:
https://draveness.me/golang/docs

goroutine and channel brief introduce

read the code below

package main

import (
    "fmt"
    "time"
    )

// 求和,并将结果送入channel中
func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    fmt.Println(sum)
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c) //17
    go sum(s[len(s)/2:], c) //-5
    fmt.Println("this is main goroutine")
    // sleep 1 sec, 主goroutine休眠1秒钟
    time.Sleep(time.Duration(1)*time.Second)
    fmt.Println("this is still main goroutine")
    x, y := <-c, <-c // receive from c

    fmt.Println("result is", x, y, x+y)
}

以上代码run出2种结果

result1:
this is main goroutine // 主goroutine
17
-5
this is still main goroutine // 主goroutine
result is 17 -5 12

result2:
this is main goroutine // 主goroutine
-5
17
this is still main goroutine // 主goroutine
result is -5 17 12
  1. 可以看到两个执行相同代码的goroutine并非先开始就先结束,它们是concurrent并发的,顺序不可预测
  2. go sum的2个goroutine,谁先打印sum谁就先向chan写入数据。由于chan不带缓存,是一个同步chan,而从chan取数据的main goroutine sleep 1 sec,因此chan缺少receiver。go sum的2个goroutine在 c <- sum 位置产生阻塞

Buffered Channels

Channels can be buffered. Provide the buffer length as the second argument to make to initialize a buffered channel
ch := make(chan int, 100)

package main

import "fmt"

func main() {
    ch := make(chan int, 2) // buffer为2的chan
    fmt.Println("send 1")
    ch <- 1
    fmt.Println("send 2")
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

以上代码运行结果如下

send 1
send 2
1
2

当buffer未满时,向chan写数据永远不会阻塞,即使没有receiver;buffer满时,写入产生阻塞。通过缓存的使用,可以尽量避免阻塞,提供应用的性能

close channel

A sender can close a channel to indicate that no more values will be sent. Only the sender should close a channel, never the receiver. Closing is only necessary when the receiver must be told there are no more values coming, such as to terminate a range loop.

select

C语言中的 select 关键字可以同时监听多个文件描述符的可读或者可写的状态,Go语言中的 select 关键字也能够让 goroutine 同时监听多个 Channel 的可读或者可写,不可读或者不可写时,select 会一直阻塞当前的线程或者Goroutine

如果有同时多个channel可读/可写,那么Go会伪随机的选择一个channel并执行对应case后的操作(pseudo-random);否则select语句会阻塞,直到某个channel满足可读/可写

下面的代码展示了golang select的使用示例

package main

import (
    "fmt"
)

func main() {
    c := make(chan int, 10)
    q := make(chan int, 10)
    fibonacci(c, q)
}

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            ele := <-c
            fmt.Println(ele, "to quit")
            quit <- ele
            x, y = y, x+y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}

上面的代码的输出有无数种可能
因为select结构会等待 c <- x 或者 <-quit 两个表达式中任意一个的返回。无论哪一个表达式返回都会立刻执行 case 中的代码,而当 select 中的两个 case 同时被触发时,会伪随机选择一个 case 执行
首次必然是case c <- x执行,其后则随机了
输出如

0 to quit
1 to quit
1 to quit
2 to quit
quit

0 to quit
quit

etc...

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:9_SooHyun

查看原文:goroutine and channel 2020-07-20

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

506 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传