兄弟连区块链培训教程并发技术3:管道通信

栏目: Go · 发布时间: 6年前

很多人喜欢 Go 语言,其实是因为Go语言有其独特的语言属性在支撑着其在编程语言界的发展,今天兄弟连Go语言+ 区块链培训 老师给大家介绍一下关于Go语言并发技术3:管道通信,下面我们一起来看一下吧。( http://bt.itxdl.cn/ )

channel 介绍

channel 提供了一种通信机制,通过它,一个 goroutine 可以想另一 goroutine 发送消息。channel 本身还需关联了一个类型,也就是 channel 可以发送数据的类型。例如: 发送 int 类型消息的 channel 写作 chan int 。

channel 创建

channel 使用内置的 make 函数创建,下面声明了一个 chan int 类型的 channel:

ch := make(chan int)

· 1

c和 map 类似,make 创建了一个底层数据结构的引用,当赋值或参数传递时,只是拷贝了一个 channel 引用,指向相同的 channel 对象。和其他引用类型一样,channel 的空值为 nil 。使用 == 可以对类型相同的 channel 进行比较,只有指向相同对象或同为 nil 时,才返回 true

channel 的读写操作

ch := make(chan int)

// write to channel

ch <- x

// read from channel

x <- ch

// another way to read

x = <- chnnel 一定要初始化后才能进行读写操作,否则会永久阻塞。

channel 一定要初始化后才能进行读写操作,否则会永久阻塞。

关闭 channel

golang 提供了内置的 close 函数对 channel 进行关闭操作。

ch := make(chan int)close(ch)

有关 channel 的关闭,你需要注意以下事项:

1. 关闭一个未初始化(nil) 的 channel 会产生 panic

2. 重复关闭同一个 channel 会产生 panic

3. 向一个已关闭的 channel 中发送消息会产生 panic

4. 从已关闭的 channel 读取消息不会产生 panic,且能读出 channel中还未被读取的消息,若消息均已读出,则会读到类型的零值。从一个已关闭的 channel 中读取消息永远不会阻塞,并且会返回一个为

5. false 的 ok-idiom,可以用它来判断 channel 是否关闭

6. 关闭 channel 会产生一个广播机制,所有向 channel 读取消息的 goroutine 都会收到消息

ch := make(chan int, 10)

ch <- 11

ch <- 12

close(ch)

forx := range ch {

fmt.Println(x)

}

x, ok := <- ch

fmt.Println(x, ok)

-----

output:

11

12

0 false

channel 的类型

channel 分为不带缓存的 channel 和带缓存的 channel。

无缓存的 channel

从无缓存的 channel 中读取消息会阻塞,直到有 goroutine 向该 channel 中发送消息;同理,向无缓存的 channel 中发送消息也会阻塞,直到有 goroutine 从 channel 中读取消息。

通过无缓存的 channel 进行通信时,接收者收到数据 happens before 发送者 goroutine 唤醒

有缓存的 channel

有缓存的 channel 的声明方式为指定 make 函数的第二个参数,该参数为 channel 缓存的容量

ch := make(chan int, 10)

· 1

有缓存的 channel 类似一个阻塞队列(采用环形数组实现)。当缓存未满时,向 channel 中发送消息时不会阻塞,当缓存满时,发送操作将被阻塞,直到有其他 goroutine 从中读取消息;相应的,当 channel 中消息不为空时,读取消息不会出现阻塞,当 channel 为空时,读取操作会造成阻塞,直到有 goroutine 向 channel 中写入消息。

ch := make(chan int, 3)

// blocked, read from empty buffered channel

<- ch

ch := make(chan int, 3)

ch <- 1

ch <- 2

ch <- 3

// blocked, send to full buffered channel

ch <- 4

通过 len 函数可以获得 chan 中的元素个数,通过 cap 函数可以得到 channel 的缓存长度。

实例

通过channel实现同步

导入依赖

import (

"fmt"

"time"

)

//语法点①:创建int类型的无缓存管道//var ch = make(chan int)varch = make(chan int,0)

funcPrinter(str string) {

for_, data := range str {

fmt.Printf("%c", data)

time.Sleep(time.Second)

}

fmt.Printf("\n")

}

func person1() {

//打印完需要7秒钟

//劳资不打印完是不会往管道中塞数据的,阻塞不死你丫的

Printer("今生注定我爱你")

//箭头指向管道内部,写数据

//在打完今生注定我爱你(耗时7秒钟)后,才写入数据

//语法点②:向管道里写数据,无论读写,箭头只能朝左

//语法点⑤:如果管道缓存已满,则阻塞等待至有人取出数据腾出空间,再写入

ch <- 666

}

func person2() {

//箭头指向管道外面,代表从管道中拿出数据,读数据

//语法点③:从管理取出数据,但不不接收

//语法点⑥:管道里没数据时,阻塞死等

<-ch

//语法点④:从管理取出数据,且使用data变量接收

//data:=<-ch

//fmt.Println("读出数据:",data)

//终于妈的可以打印了

Printer("FUCKOFF")

}

func main() {

go person1()

go person2()

//主协程赖着不死

for {

time.Sleep(time.Second)

}

}

通过channel实现同步和数据交互

package main

import (

"fmt"

"time"

)

func main() {

//创建无缓存管道

ch := make(chan string)

//5、主协程结束

defer fmt.Println("主协程也结束")

//子协程负责写数据

go func() {

//3、结束任务

defer fmt.Println("子协程调用完毕")

//1、缓缓打印2次序号

for i := 0; i < 2; i++ {

fmt.Println("子协程 i= ", i)

time.Sleep(time.Second)

}

//2、向管道发送数据

ch <- "我是子协程,工作完毕"

}()

//4、阻塞接收

str := <-ch

fmt.Println("str = ", str)

}

无缓冲的channel

package main

import (

"fmt"

"time"

)

func main() {

//创建一个无缓冲的管道

ch := make(chan int, 1)

//长度0,缓存能力0

fmt.Printf("len(ch) = %d, cap(ch)=%d\n", len(ch), cap(ch))

go func() {

//向管道中存入0,被阻塞,存入1,被阻塞,存入2

for i := 0; i < 3; i++ {

fmt.Println("子协程: i = ", i)

ch <- i

fmt.Println("5秒以内被打印出来给杰神100万!")

}

}()

//睡眠2秒

time.Sleep(5 * time.Second)

//读取0,被阻塞,读取1,被阻塞,读取2

for i := 0; i < 3; i++ {

num := <-ch

fmt.Println("num = ", num)

}

}

有缓存的channel

package main

import (

"fmt"

"time"

)

func main() {

//创建3缓存的管道

ch := make(chan int, 3)

//长度0,缓存能力3(即使没人读,也能写入3个值)

fmt.Printf("len(ch) = %d, cap(ch) = %d\n", len(ch), cap(ch))

//一次性存入3个:012,3456789

go func() {

for i := 0; i < 10; i++ {

ch <- i

fmt.Printf("子协程存入[%d]: len(ch) = %d, cap(ch) = %d\n", i, len(ch), cap(ch))

//time.Sleep(1 * time.Second)

}

}()

//time.Sleep(5 * time.Second)

//一次性读取3个:012,345,678,9

for i := 0; i < 10; i++ {

num := <-ch

fmt.Println("num = ", num)

}

time.Sleep(1*time.Nanosecond)

}

更多区块链视频教程/源码/课件/学习资料-企鹅QUN:591229276


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

从0开始做运营 入门篇

从0开始做运营 入门篇

张亮 / 4.99元

此书是《从零开始做运营》系列的入门篇。 在互联网产品经理热的今天,关于传统的网站与产品运营的书籍一直非常缺乏,很多有志于互联网行业的年轻人并不明白一款产品、一个网站的策划、上线、成长、成熟直到衰落的过程中,除了产品和网站本身的设计之外,还有一块非常重要的工作是针对网站与产品生命周期的持续运营。 网站与产品运营是一个非常辛苦而非常有趣的事情,希望本书可以为有志于从事互联网网站与产品运营的......一起来看看 《从0开始做运营 入门篇》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

MD5 加密
MD5 加密

MD5 加密工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具