goroutine 及channel

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

本文主要介绍goroutine 和channel的使用。

基础知识介绍

goroutine 是 golang 中在语言级别实现的轻量级线程,仅仅利用 go 就能立刻起一个新线程。多线程会引入线程之间的同步问题,在 golang 中可以使用 channel 作为同步的工具。

通过 channel 可以实现两个 goroutine 之间的通信。

创建一个 channel, make(chan TYPE {, NUM}) TYPE 指的是 channel 中传输的数据类型,第二个参数是可选的,指的是 channel 的容量大小。

向 channel 传入数据, CHAN <- DATA , CHAN 指的是目的 channel 即收集数据的一方, DATA 则是要传的数据。

从 channel 读取数据, DATA := <-CHAN ,和向 channel 传入数据相反,在数据输送箭头的右侧的是 channel,形象地展现了数据从隧道流出到变量里。

举三个例子


package main
/**
使用通道,类似于多线程计算
 */
import (
    "fmt"
    "math/rand"
    "time"
)

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        time.Sleep(time.Duration(rand.Int31n(10)) * time.Millisecond)
        sum += v
    }
    c <- sum // 把 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, x+y)
}
/**
通道缓冲区, 关闭通道
 */

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)
    // range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
    // 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
    // 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
    // 会结束,从而在接收第 11 个数据的时候就阻塞了。
    for i := range c {
        fmt.Println(i)
    }
    fmt.Print("finish")
}
package main

import (
    "fmt"
    "time"
)

func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s, (i+1)*100)
    }
}
func say2(s string, ch chan int) {
    for i := 0; i < 5; i++ {
        time.Sleep(150 * time.Millisecond)
        fmt.Println(s, (i+1)*150)
    }
    ch <- 0
    close(ch)//关闭通道并不会丢失里面的数据,只是让读取通道数据的时候不会读完之后一直阻塞等待新数据写入
}

func main() {
    ch := make(chan int)
    go say2("world", ch)
    say("hello")
    fmt.Println(<-ch)//主函数会等待信道的值才会结束。
}


//注释掉的方法,在执行中会发现,say2方法并没有执行完成。这是因为goroutine 还没来得及跑完 5 次的时候,主函数已经退出了。通过引入信道,可以解决这个问题。

/**
package main
import (
    "fmt"
    "time"
)
func say(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(100 * time.Millisecond)
        fmt.Println(s, (i+1)*100)
    }
}
func say2(s string) {
    for i := 0; i < 5; i++ {
        time.Sleep(150 * time.Millisecond)
        fmt.Println(s, (i+1)*150)
    }
}
func main() {
    go say2("world")
    say("hello")
}
 */

上面三个例子都是关于多线程和线程间通信的例子。

Channel 控制读写权限

go func(c chan int) { //读写均可的channel c } (a)
go func(c <- chan int) { //只读的Channel } (a)
go func(c chan <- int) { //只写的Channel } (a)


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

本文来自:简书

感谢作者:不怕天黑_0819

查看原文:goroutine 及channel

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

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