Go语言那些事儿之管道的关闭

简介: 之前我们提到了怎么定义管道,讲了管道的读取和写入。那么今天我们就来讲一讲管道的关闭。

Go语言那些事儿之管道的关闭

之前我们提到了怎么定义管道,讲了管道的读取和写入。那么今天我们就来讲一讲管道的关闭。

先来看一个简单的例子:

func main() {
    ch := make(chan int,10)
    for i := 0;i < 5;i++{
        ch <- i*i
    }
    close(ch)

    for x:= range ch {
        fmt.Println(x)
    }
}

先思考一下它会输出什么?

没错它的输出结果是:

0
1
4
9
16

这段的代码就是定义一个管道,然后遍历零到四,将零到四的平方塞入管道。我们知道这个管道定义时,被赋予了10的缓存能力,所以能够缓存10个单位的数据。而我们这里只需要存5个单位,你会想是不是还有5个单位是空闲的?是的。

下面我们再看一看多个协程并发读写管道:

func main()  {
    ch := make(chan int,10)

    go func() {
        for i:=0;i<5;i++{
            ch <- i * i
            fmt.Println("写入",i*i)
            time.Sleep(1 * time.Second)

        }
        // The close built-in function closes a channel, which must be either
        // bidirectional or send-only. It should be executed only by the sender,
        // never the receiver, and has the effect of shutting down the channel after
        // the last sent value is received. After the last value has been received
        // from a closed channel c, any receive from c will succeed without
        // blocking, returning the zero value for the channel element. The form
        //    x, ok := <-c
        // will also set ok to false for a closed channel.
        close(ch)
        fmt.Println("管道已关闭,写入协程结束")
    }()
    go func() {
        for x:= range ch{
            fmt.Println("读出",x)
        }
        fmt.Println("读取协程结束")
    }()

    time.Sleep(6 * time.Second)
    fmt.Println("GAME OVER")
}

运行结果是:

写入 0
读出 0
读出 1
写入 1
写入 4
读出 4
写入 9
读出 9
写入 16
读出 16
读取协程结束
管道已关闭,写入协程结束
GAME OVER

这段代码的作用是建立一个缓存能力为10的管道,建立两条协程。一条协程用来将零到四的平方写入管道,写完之后关闭管道。另一条协程是用来将管道内的数据读出。

由于两条协程是并发的,所以一条协程往管道里写入一条数据,马上另一条协程就往管道里读取一条数据。这里那条写入数据的协程关闭了管道,那么就会通知那边不需要再继续从管道中读取数据了,那么另外一条协程就不会往管道里面读取数据了。如果没有close(ch),也就是不关闭管道,那么另一条协程就会不断读取管道,直到主协程正常结束,那条子协程才会结束。

我们需要注意,内建函数close函数是用来关闭通道的,并且只有双向的和仅发送的管道才能被关闭。

还有一点需要注意的是,这个close函数需要由发送方执行,而不是由接收方执行。从一个关闭的通道接收完最后一个值后,从该管道接收的任何值都将成功,不会阻塞,并返回零值。但是对于x, ok := <-c,将会为关闭的管道的ok值赋予false值。

目录
相关文章
|
1天前
|
Java 编译器 Go
探索Go语言的性能优化技巧
在本文中,我们将深入探讨Go语言的底层机制,以及如何通过代码层面的优化来提升程序性能。我们将讨论内存管理、并发控制以及编译器优化等关键领域,为你提供一系列实用的技巧和最佳实践。
|
1天前
|
Cloud Native Go API
Go语言在微服务架构中的创新应用与实践
本文深入探讨了Go语言在构建高效、可扩展的微服务架构中的应用。Go语言以其轻量级协程(goroutine)和强大的并发处理能力,成为微服务开发的首选语言之一。通过实际案例分析,本文展示了如何利用Go语言的特性优化微服务的设计与实现,提高系统的响应速度和稳定性。文章还讨论了Go语言在微服务生态中的角色,以及面临的挑战和未来发展趋势。
|
1天前
|
安全 Go 调度
探索Go语言的并发模式:协程与通道的协同作用
Go语言以其并发能力闻名于世,而协程(goroutine)和通道(channel)是实现并发的两大利器。本文将深入了解Go语言中协程的轻量级特性,探讨如何利用通道进行协程间的安全通信,并通过实际案例演示如何将这两者结合起来,构建高效且可靠的并发系统。
|
1天前
|
安全 Go 开发者
破译Go语言中的并发模式:从入门到精通
在这篇技术性文章中,我们将跳过常规的摘要模式,直接带你进入Go语言的并发世界。你将不会看到枯燥的介绍,而是一段代码的旅程,从Go的并发基础构建块(goroutine和channel)开始,到高级模式的实践应用,我们共同探索如何高效地使用Go来处理并发任务。准备好,让Go带你飞。
|
2天前
|
运维 Go 开发者
Go语言在微服务架构中的应用与优势
本文深入探讨了Go语言在构建微服务架构中的独特优势和实际应用。通过分析Go语言的核心特性,如简洁的语法、高效的并发处理能力以及强大的标准库支持,我们揭示了为何Go成为开发高性能微服务的首选语言。文章还详细介绍了Go语言在微服务架构中的几个关键应用场景,包括服务间通信、容器化部署和自动化运维等,旨在为读者提供实用的技术指导和启发。
|
2天前
|
安全 Go 调度
探索Go语言的并发之美:goroutine与channel
在这个快节奏的技术时代,Go语言以其简洁的语法和强大的并发能力脱颖而出。本文将带你深入Go语言的并发机制,探索goroutine的轻量级特性和channel的同步通信能力,让你在高并发场景下也能游刃有余。
|
3天前
|
Go 开发者
Go语言中的并发编程:从基础到实践
在当今的软件开发中,并发编程已经成为了一项不可或缺的技能。Go语言以其简洁的语法和强大的并发支持,成为了开发者们的首选。本文将带你深入了解Go语言中的并发编程,从基础概念到实际应用,帮助你掌握这一重要的编程技能。
|
4天前
|
Go
使用go语言将A助手加入项目中
使用go语言将A助手加入项目中
13 2
|
3天前
|
安全 Go 调度
探索Go语言的并发模型:Goroutine与Channel的魔力
本文深入探讨了Go语言的并发模型,不仅解释了Goroutine的概念和特性,还详细讲解了Channel的用法和它们在并发编程中的重要性。通过实际代码示例,揭示了Go语言如何通过轻量级线程和通信机制来实现高效的并发处理。
|
3天前
|
存储 安全 Go
Go语言切片:从入门到精通的深度探索###
本文深入浅出地剖析了Go语言中切片(Slice)这一核心概念,从其定义、内部结构、基本操作到高级特性与最佳实践,为读者提供了一个全面而深入的理解。通过对比数组,揭示切片的灵活性与高效性,并探讨其在并发编程中的应用优势。本文旨在帮助开发者更好地掌握切片,提升Go语言编程技能。 ###