go语言通道关闭 go语言运行

Go语言文件操作本文主要介绍了Go语言中文件读写的相关操作 。
文件是什么?
计算机中的文件是存储在外部介质(通常是磁盘)上的数据集合,文件分为文本文件和二进制文件 。
os.Open() 函数能够打开一个文件,返回一个 *File 和一个 err。对得到的文件实例调用 close() 方法能够关闭文件 。
为了防止文件忘记关闭,我们通常使用defer注册文件关闭语句 。
Read方法定义如下:
它接收一个字节切片,返回读取的字节数和可能的具体错误,读到文件末尾时会返回 0 和 io.EOF。举个例子:
使用for循环读取文件中的所有数据 。
bufio是在file的基础上封装了一层API,支持更多的功能 。
io/ioutil 包的 ReadFile 方法能够读取完整的文件 , 只需要将文件名作为参数传入 。
os.OpenFile() 函数能够以指定模式打开文件 , 从而实现文件写入相关功能 。
其中:
name :要打开的文件名flag :打开文件的模式 。模式有以下几种:
perm :文件权限,一个八进制数 。r(读)04,w(写)02,x(执行)01 。
golang - channel通过var声明或者make函数创建的channel变量是一个存储在函数栈帧上的指针,占用8个字节,指向堆上的hchan结构体
源码包中src/runtime/chan.go定义了hchan的数据结构如下:
hchan结构体的主要组成部分有四个:
用来保存goroutine之间传递数据的循环数组:buf
用来记录此循环数组当前发送或接收数据的下标值:sendx和recvx
用于保存向该chan发送和从该chan接收数据被阻塞的goroutine队列: sendq 和 recvq
保证channel写入和读取数据时线程安全的锁:lock
环形数组作为channel 的缓冲区 数组的长度就是定义channnel 时channel 的缓冲大小
在hchan 中包括了读/写 等待队列 , waitq是一个双向队列 , 包括了一个头结点和尾节点 。每个节点是一个sudog结构体变量
channel有2种类型:无缓冲、有缓冲 , 在创建时 make(chan type cap)通过cap 设定缓冲大小
channel有3种模式:写操作模式(单向通道)、读操作模式(单向通道)、读写操作模式(双向通道)
channel有3种状态:未初始化、正常、关闭
如下几种状态会引发panic
channel 是线程安全的,channel的底层实现中,hchan结构体中采用Mutex锁来保证数据读写安全 。在对循环数组buf中的数据进行入队和出队操作时,必须先获取互斥锁,才能操作channel数据
go语言无缓冲的channel无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道 。
这种类型的通道要求发送goroutine和接收goroutine同时准备好,才能完成发送和接收操作 。否则,通道会导致先执行发送或接收操作的 goroutine 阻塞等待 。
这种对通道进行发送和接收的交互行为本身就是同步的 。其中任意一个操作都无法离开另一个操作单独存在 。
阻塞:由于某种原因数据没有到达,当前协程(线程)持续处于等待状态,直到条件满足 , 才接触阻塞 。
同步:在两个或多个协程(线程)间,保持数据内容一致性的机制 。
下图展示两个 goroutine 如何利用无缓冲的通道来共享一个值:
在第 1 步,两个 goroutine 都到达通道,但哪个都没有开始执行发送或者接收 。
在第 2 步,左侧的 goroutine 将它的手伸进了通道,这模拟了向通道发送数据的行为 。这时,这个 goroutine 会在通道中被锁住,直到交换完成 。
在第 3 步,右侧的 goroutine 将它的手放入通道,这模拟了从通道里接收数据 。这个 goroutine 一样也会在通道中被锁住,直到交换完成 。
在第 4 步和第 5 步,进行交换,并最终,在第 6 步 , 两个 goroutine 都将它们的手从通道里拿出来,这模拟了被锁住的 goroutine 得到释放 。两个 goroutine 现在都可以去做别的事情了 。
如果没有指定缓冲区容量,那么该通道就是同步的 , 因此会阻塞到发送者准备好发送和接收者准备好接收 。
无缓冲channel: —— 同步通信
channel使用【译文】 原文地址
channel是Go语言go语言通道关闭的一个标志性特性go语言通道关闭 , 为go协程之间的数据交互提供一种非常强大的方式,而不需要使用锁机制 。
本文将讨论channel的两个重要属性 , 一个是控制协程间数据发送和接收,以及对channel本身控制 。
首先讨论下关闭的channel特性 。一旦channel被关闭之后,就不能再继续发送数据给该channel,但是还是可以继续接收channel中的数据 。如下所示go语言通道关闭:
output:
上述例子显示即使ch在for循环之前已经关闭,但还是可以正常的读取缓存中的true值 , 读完之后ok就会被赋值为false表示channel已经关闭,而且value值为对应channel类型bool的默认零值false 。只要不停地从关闭的channel接收,就会无限的返回默认值和false 。可以将for循环次数改大点试试即可验证 。
通过以上例子可以发现 , 关闭的channel可以继续接收读取操作,这种特征是有用的 。在使用range读取带缓存的channel时就会用到,一旦channel关闭,读取完缓存中数据就会停止接收数据退出 。
将前面的例子改为如下:
output:
上面的例子就没有false打出来go语言通道关闭了 。正好是写入channel里面的两个值 。
channel与select结合更能发挥出其作用,让我们看一个例子:
上面的例子,因为finish在主协程中发送之后,马上就会在select中接收,并执行done.Done() 。主协程wait马上会退出整个程序就结束 。但是这里面存在一个问题,如果在select中没有添加finish case的话,主协程就永远发送不了数据到finish这个channel,因为其不带缓存 。这里就可以通过将finish改成带缓存的channel,或者可以让select中的finish不会阻塞 。
但是出现多个协程都在接收finish通道中的数据的话,就需要发送对应协程数量的值到channel中才能解决上面的问题 。但是具体有多少个协程这往往是不好确定的,因为有些协程可能是程序其go语言通道关闭他部分创建的 。一个比较好的选择就是通过使用关闭通道的方法来实现各协程能正常接收并结束 。
如下所示:
output:
上面的例子就是使用了关闭的channel可以无限地接收到反馈数据 。这样每个协程都能从finish通道中读到关闭信息并执行done.Done()使得主协程wait能退出 。并且不需要关注多少个协程数,就能正确的让所有协程读到finish通道信息 。
channel的这个特性,可以让程序员无需关注后台具体执行协程个数,确保每个协程都能接收到通道关闭信息,而无需担心死锁问题 。
通过上面的例子我们也发现每个协程并不需要从通道中读取对应类型的数据 , 只需让接收操作能执行就行,让select不被阻塞 。所以可以使用空结构体类型,我们可以改成如下:
这里我们只关注通道是否关闭这个信号 , 而不需要关注通道里面的数据,所以可使用空结构体类型通道 。
第二个要讨论的是nil通道:如果定义了一个channel变量没有被初始化,或者被赋值为nil,那么该chennel总是处于阻塞状态 。如下所示:
执行结果为:
因为channel为nil无法发送数据,当然也不能接收数据:
这个似乎看起来不是很重要,但是如果你想使用关闭channel来等待多个channel关闭的话,这个特性就有用处了 。先看下面的例子:
WaitMany()函数看起来好像是一个等待通道a和b关闭的好方法,但是存在一个问题 。假设a通道先关闭,case -a就会变成非阻塞 。因为bclosed还是false,程序就会进入到一个死循环当中,导致b通道永远无法确认关闭 。
一个安全的方法就是使用nil通道总是阻塞的特点,如下所示:
上面的例子我们在WaitMany函数当中 , 当a或者b关闭时,case可执行了将对应的通道赋值为nil , 让其阻塞这样就可以等待另一个通道关闭 。当nil通道是select语句的一部分时,它会被有效地忽略,因此nil通道a会从select中删除它,只留下b,直到它被关闭,退出循环 。
【go语言通道关闭 go语言运行】 总之,closed和nil通道的简单属性对写出优质的go程序是很有用的,可以用来创建高并发程序 。
Golang入门到项目实战 | golang并发变成之通道channel Go提供了一种称为通道的机制,用于在goroutine之间共享数据 。当您作为goroutine执行并发活动时,需要在goroutine之间共享资源或数据 , 通道充当goroutine之间的管道(管道)并提供一种机制来保证同步交换 。
根据数据交换的行为,有两种类型的通道:无缓冲通道和缓冲通道 。无缓冲通道用于执行goroutine之间的同步通信,而缓冲通道用于执行异步通信 。无缓冲通道保证在发送和接收发生的瞬间两个goroutine之间的交换 。缓冲通道没有这样的保证 。
通道由make函数创建 , 该函数指定chan关键字和通道的元素类型 。
这是创建无缓冲和缓冲通道的代码块:
语法
使用内置函数make创建无缓冲和缓冲通道 。make的第一个参数需要关键字chan,然后是通道允许交换的数据类型 。
这是将值发送到通道的代码块需要使用-运算符:
语法
一个包含5个值的缓冲区的字符串类型的goroutine1通道 。然后我们通过通道发送字符串“Australia” 。
这是从通道接收值的代码块:
语法
- 运算符附加到通道变量(goroutine1)的左侧,以接收来自通道的值 。
在无缓冲通道中,在接收到任何值之前没有能力保存它 。在这种类型的通道中,发送和接收goroutine在任何发送或接收操作完成之前的同一时刻都准备就绪 。如果两个goroutine没有在同一时刻准备好,则通道会让执行其各自发送或接收操作的goroutine首先等待 。同步是通道上发送和接收之间交互的基础 。没有另一个就不可能发生 。
在缓冲通道中,有能力在接收到一个或多个值之前保存它们 。在这种类型的通道中,不要强制goroutine在同一时刻准备好执行发送和接收 。当发送和接收阻塞时也有不同的条件 。只有当通道中没有要接收的值时,接收才会阻塞 。仅当没有可用缓冲区来放置正在发送的值时,发送才会阻塞 。
实例
运行结果
关于go语言通道关闭和go语言运行的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。

    推荐阅读