• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

GO channel

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
package main
import (
    "fmt"
)
func main() {
    // 构建一个通道
    ch := make(chan int)
    // 开启一个并发匿名函数
    go func() {
        fmt.Println("start goroutine")
        // 通过通道通知main的goroutine
        ch <- 0
        fmt.Println("exit goroutine")
    }()
    fmt.Println("wait goroutine")
    // 等待匿名goroutine
    <-ch
    fmt.Println("all done")
}

使用通道接收数据

通道接收同样使用<-操作符,通道接收有如下特性:
① 通道的收发操作在不同的两个 goroutine 间进行。

由于通道的数据在没有接收方处理时,数据发送方会持续阻塞,因此通道的接收必定在另外一个 goroutine 中进行。

② 接收将持续阻塞直到发送方发送数据。

如果接收方接收时,通道中没有发送方发送数据,接收方也会发生阻塞,直到发送方发送数据为止。

③ 每次接收一个元素。
通道一次只能接收一个数据元素。

通道的数据接收一共有以下 4 种写法。

1) 阻塞接收数据

阻塞模式接收数据时,将接收变量作为<-操作符的左值,格式如下:

data := <-ch

执行该语句时将会阻塞,直到接收到数据并赋值给 data 变量。

2) 非阻塞接收数据

使用非阻塞方式从通道接收数据时,语句不会发生阻塞,格式如下:

data, ok := <-ch

  • data:表示接收到的数据。未接收到数据时,data 为通道类型的零值。
  • ok:表示是否接收到数据。


非阻塞的通道接收方法可能造成高的 CPU 占用,因此使用非常少。如果需要实现接收超时检测,可以配合 select 和计时器 channel 进行,可以参见后面的内容。

3) 接收任意数据,忽略接收的数据

阻塞接收数据后,忽略从通道返回的数据,格式如下:

<-ch

执行该语句时将会发生阻塞,直到接收到数据,但接收到的数据会被忽略。这个方式实际上只是通过通道在 goroutine 间阻塞收发实现并发同步。

 

通道结合rpc

package main
import (
    "errors"
    "fmt"
    "time"
)
// 模拟RPC客户端的请求和接收消息封装
func RPCClient(ch chan string, req string) (string, error) {
    // 向服务器发送请求
    ch <- req
    // 等待服务器返回
    select {
    case ack := <-ch: // 接收到服务器返回数据
        return ack, nil
    case <-time.After(time.Second): // 超时
        return "", errors.New("Time out")
    }
}

//使用了 time 包提供的函数 After(),从字面意思看就是多少时间之后,其参数是 time 包的一个常量,time.Second 表示 1 秒。
//time.After 返回一个通道,这个通道在指定时间后,通过通道返回当前时间。
//RPCClient() 函数中,执行到 select 语句时,第 9 行和第 11 行的通道操作会同时开启。
//如果第 9 行的通道先返回,则执行第 10 行逻辑,表示正常接收到服务器数据;如果第 11 行的通道先返回,则执行第 12 行的逻辑,表示请求超时,返回错误。

// 模拟RPC服务器端接收客户端请求和回应
func RPCServer(ch chan string) {
    for {
        // 接收客户端请求
        data := <-ch
        // 打印接收到的数据
        fmt.Println("server received:", data)
        // 通过睡眠函数让程序执行阻塞2秒的任务
        time.Sleep(time.Second * 2)
        // 反馈给客户端收到
        ch <- "roger"
    }
}
func main() {
    // 创建一个无缓冲字符串通道
    ch := make(chan string)
    // 并发执行服务器逻辑
    go RPCServer(ch)
    // 客户端请求数据和接收数据
    recv, err := RPCClient(ch, "hi")
    if err != nil {
        // 发生错误打印
        fmt.Println(err)
    } else {
        // 正常接收到数据
        fmt.Println("client received", recv)
    }
}

 

关闭通道       通道可以访问但不能发送数据

// 创建一个整型的通道
ch := make(chan int)
// 关闭通道
close(ch)
// 打印通道的指针, 容量和长度
fmt.Printf("ptr:%p cap:%d len:%d\n", ch, cap(ch), len(ch))
// 给关闭的通道发送数据
ch <- 1

 

转载于:https://my.oschina.net/shunshun/blog/3028737


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Golang任务队列策略--读《JOBQUEUESINGO》发布时间:2022-07-10
下一篇:
Go语言切片(Slice)发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap