golang 学习 - chan

1. 通道

// _通道_ 是连接多个 Go 协程的管道。你可以从一个 Go 协程
// 将值发送到通道,然后在别的 Go 协程中接收。package mainimport "fmt"func main() {// 使用 `make(chan val-type)` 创建一个新的通道。// 通道类型就是他们需要传递值的类型。messages := make(chan string)// 使用 `channel <-` 语法 _发送_ 一个新的值到通道中。这里// 我们在一个新的 Go 协程中发送 `"ping"` 到上面创建的// `messages` 通道中。go func() { messages <- "ping" }()// 使用 `<-channel` 语法从通道中 _接收_ 一个值。这里// 将接收我们在上面发送的 `"ping"` 消息并打印出来。msg := <-messagesfmt.Println(msg)
}

2. 通道缓存

// 默认通道是 _无缓冲_ 的,这意味着只有在对应的接收(`<- chan`)
// 通道准备好接收时,才允许进行发送(`chan <-`)。_可缓存通道_
// 允许在没有对应接收方的情况下,缓存限定数量的值。package mainimport "fmt"func main() {// 这里我们 `make` 了一个通道,最多允许缓存 2 个值。messages := make(chan string, 2)// 因为这个通道是有缓冲区的,即使没有一个对应的并发接收// 方,我们仍然可以发送这些值。messages <- "buffered"messages <- "channel"// 然后我们可以像前面一样接收这两个值。fmt.Println(<-messages)fmt.Println(<-messages)
}

3. 通道同步

// 我们可以使用通道来同步 Go 协程间的执行状态。这里是一个
// 使用阻塞的接受方式来等待一个 Go 协程的运行结束。package mainimport "fmt"
import "time"// 这是一个我们将要在 Go 协程中运行的函数。`done` 通道
// 将被用于通知其他 Go 协程这个函数已经工作完毕。
func worker(done chan bool) {fmt.Print("working...")time.Sleep(time.Second)fmt.Println("done")// 发送一个值来通知我们已经完工啦。done <- true
}func main() {// 运行一个 worker Go协程,并给予用于通知的通道。done := make(chan bool, 1)go worker(done)// 程序将在接收到通道中 worker 发出的通知前一直阻塞。<-done
}

4. 通道方向

// 当使用通道作为函数的参数时,你可以指定这个通道是不是
// 只用来发送或者接收值。这个特性提升了程序的类型安全性。package mainimport "fmt"// `ping` 函数定义了一个只允许发送数据的通道。尝试使用这个通
// 道来接收数据将会得到一个编译时错误。
func ping(pings chan<- string, msg string) {pings <- msg
}// `pong` 函数允许通道(`pings`)来接收数据,另一通道
// (`pongs`)来发送数据。
func pong(pings <-chan string, pongs chan<- string) {msg := <-pingspongs <- msg
}func main() {pings := make(chan string, 1)pongs := make(chan string, 1)ping(pings, "passed message")pong(pings, pongs)fmt.Println(<-pongs)
}

5. 通道选择器

package mainimport "time"
import "fmt"func main() {// 在我们的例子中,我们将从两个通道中选择。c1 := make(chan string)c2 := make(chan string)// 各个通道将在若干时间后接收一个值,这个用来模拟例如// 并行的 Go 协程中阻塞的 RPC 操作go func() {time.Sleep(time.Second * 1)c1 <- "one"}()go func() {time.Sleep(time.Second * 2)c2 <- "two"}()// 我们使用 `select` 关键字来同时等待这两个值,并打// 印各自接收到的值。for i := 0; i < 2; i++ {select {case msg1 := <-c1:fmt.Println("received", msg1)case msg2 := <-c2:fmt.Println("received", msg2)}}
}

6. 超时处理

package mainimport "time"
import "fmt"func main() {// 在我们的例子中,假如我们执行一个外部调用,并在 2 秒后// 通过通道 `c1` 返回它的执行结果。c1 := make(chan string, 1)go func() {time.Sleep(time.Second * 2)c1 <- "result 1"}()// 这里是使用 `select` 实现一个超时操作。// `res := <- c1` 等待结果,`<-Time.After` 等待超时// 时间 1 秒后发送的值。由于 `select` 默认处理第一个// 已准备好的接收操作,如果这个操作超过了允许的 1 秒// 的话,将会执行超时 case。select {case res := <-c1:fmt.Println(res)case <-time.After(time.Second * 1):fmt.Println("timeout 1")}}

7. 定时器

package mainimport "time"
import "fmt"func main() {// 定时器表示在未来某一时刻的独立事件。你告诉定时器// 需要等待的时间,然后它将提供一个用于通知的通道。// 这里的定时器将等待 2 秒。timer1 := time.NewTimer(time.Second * 2)// `<-timer1.C` 直到这个定时器的通道 `C` 明确的发送了// 定时器失效的值之前,将一直阻塞。<-timer1.Cfmt.Println("Timer 1 expired")// 如果你需要的仅仅是单纯的等待,你需要使用 `time.Sleep`。// 定时器是有用原因之一就是你可以在定时器失效之前,取消这个// 定时器。这是一个例子timer2 := time.NewTimer(time.Second)go func() {<-timer2.Cfmt.Println("Timer 2 expired")}()stop2 := timer2.Stop()if stop2 {fmt.Println("Timer 2 stopped")}
}

8. 打点器

package mainimport "time"
import "fmt"func main() {// 打点器和定时器的机制有点相似:一个通道用来发送数据。// 这里我们在这个通道上使用内置的 `range` 来迭代值每隔// 500ms 发送一次的值。ticker := time.NewTicker(time.Millisecond * 500)go func() {for t := range ticker.C {fmt.Println("Tick at", t)}}()// 打点器可以和定时器一样被停止。一旦一个打点停止了,// 将不能再从它的通道中接收到值。我们将在运行后 1500ms// 停止这个打点器。time.Sleep(time.Millisecond * 1500)ticker.Stop()fmt.Println("Ticker stopped")
}

9. 工作池

package mainimport "fmt"
import "time"// 这是我们将要在多个并发实例中支持的任务了。这些执行者
// 将从 `jobs` 通道接收任务,并且通过 `results` 发送对应
// 的结果。我们将让每个任务间隔 1s 来模仿一个耗时的任务。
func worker(id int, jobs <-chan int, results chan<- int) {for j := range jobs {fmt.Println("worker", id, "processing job", j)time.Sleep(time.Second)results <- j * 2}
}func main() {// 为了使用 worker 工作池并且收集他们的结果,我们需要// 2 个通道。jobs := make(chan int, 100)results := make(chan int, 100)// 这里启动了 3 个 worker,初始是阻塞的,因为// 还没有传递任务。for w := 1; w <= 3; w++ {go worker(w, jobs, results)}// 这里我们发送 9 个 `jobs`,然后 `close` 这些通道// 来表示这些就是所有的任务了。for j := 1; j <= 9; j++ {jobs <- j}close(jobs)// 最后,我们收集所有这些任务的返回值。for a := 1; a <= 9; a++ {<-results}
}

golang 学习 - chan以及chan的一下用例相关推荐

  1. golang学习笔记(基础篇)

    LCY~~Golang学习笔记 一.Go语言开发环境 ##安装Go开发包以及VsCode Go开发包与vscode配置安装教程网址:https://www.liwenzhou.com/posts/Go ...

  2. 118云原生编程语言Golang学习笔记

    Golang学习笔记 文章目录 1.Go简介 1.1 简介 1.2 设计初衷 1.3 Golang vs Java 1.4 应用领域 1.5 用go语言的公司 2.Go下载和安装 2.1 开发工具 2 ...

  3. Golang学习--TOML配置处理

    Golang学习–TOML配置处理 文章目录 Golang学习--TOML配置处理 配置工具的选择 toml的使用 配置的单例模式 配置的更新 POSIX信号 在POSIX.1-1990标准中定义的信 ...

  4. Golang学习-基础命令

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. . Golang学习-基础命令 一.go run 用于运行命令源码文件,只能接收一个命令源码文件以及若干个库源码文件作为 ...

  5. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

  6. Golang学习(10)——bufio包

    Golang学习 - bufio 包 ------------------------------------------------------------ // bufio 包实现了带缓存的 I/ ...

  7. Golang学习(12)——regex包

    Golang学习 - regexp 包 ------------------------ // 函数 // 判断在 b(s.r)中能否找到 pattern 所匹配的字符串 func Match(pat ...

  8. Duang~ Golang 学习初探

    Duang~  Golang学习初步体验,一直以来都对Go语言有一定的喜感,今天花了点时间初步的了解了下Go,其实很多东西弄个小例子go run下会明白很多东西的. 本人开发工具使用的是GoSubli ...

  9. golang学习笔记(五):数组的定义和使用

    golang 学习笔记 数组定义 数组是一系列相同数据类型在内存中有序存储的数据集合 var 数组名 [元素个数]数据类型//定义了10个整型变量的数组元素var arr [10]int//通过下标找 ...

最新文章

  1. ***警告即将发起重大*** 谁会是下一个目标?
  2. 获得诺贝尔奖的底层小职员 | 从来没有一个高手,是在一夜之间强大起来的
  3. 刚体Collider包围测试
  4. go语言中的闭包结构
  5. 2017年11月1号复习
  6. python语言1002python语言_PYTHON语言学习
  7. 【WS-Federation】到底有多少公司在用WS-Federation
  8. Qt:Windows编程—Qt实现进程管理
  9. 钢琴块2电脑版_云上钢琴学生端电脑版|云上钢琴学生端 V2.3.1 最新PC版 下载_当下软件园...
  10. C++中string::find()函数和string::npos函数的使用
  11. python如何导入类里_Python导入模块中的所有类(98)
  12. 删除web项目服务器,删除 Tomcat-webapps 目录自带项目【测试可行】
  13. Windows添加.NET Framework 3.0 NetFx3 失败 - 状态为:0x800f0950
  14. 未受信任的企业级开发者_“未受信任的企业级开发者”是什么意思?怎么解决?...
  15. 批量取消关注和删除微博
  16. 解决WARNING: Ignoring invalid distribution -pencv-python (c:\users\lhw\anaconda3\lib\site-packages)
  17. 如何用自己的电脑作为服务器搭一个网站
  18. 如何使用CAD软件来修改表格中CAD字体颜色?
  19. 3D打印将对零售模式产生颠覆影响,能否抓住机遇
  20. MySQL 服务无法打开的解决方法

热门文章

  1. Scrapy中的item和pipline
  2. 笔记本蓝牙模块转USB接口方法
  3. PN532模块复制IC加密卡
  4. 2007-11-20 多普达828+不完全技术分析 [zozo转及对话]
  5. C++ | 大小写字母转换
  6. win10 文件夹设置区分大小写
  7. 华为A1路由器虚拟服务器,华为a1路由器怎么用手机设置DMZ主机
  8. rt3290+linux驱动下载,Ralink雷凌RT3290蓝牙驱动
  9. 【spring】spring异步执行的使用与源码分析
  10. 网站收录量如何提高?