go语言 channel

基础

  1. channel类似于c中的pipe,管道
  2. 解决协程同步问题
  3. 解决数据共享问题
  4. goroutine核心思想是:通过通信来共享内存,而不是共享内存来通信

语法

  1. 语法
   make(chan Type)  //等价于make(chan Type, 0)
   make(chan Type, capacity)
  1. make创建,返回的是一个引用
  2. 当 参数capacity= 0 时,channel 是无缓冲阻塞读写的;当capacity > 0 时,channel 有缓冲、是非阻塞的,直到写满 capacity个元素才阻塞写入。
  3. 读写 channel
channel <- value      //发送value到channel
<-channel             //接收并将其丢弃
x := <-channel        //从channel中接收数据,并赋值给x
x, ok := <-channel    //功能同上,同时检查通道是否已关闭或者是否为空

channel的缓冲类型

阻塞:由于某种原因数据没有到达,当前协程(线程)持续处于等待状态,直到条件满足,才接触阻塞。
同步:在两个或多个协程(线程)间,保持数据内容一致性的机制。

无缓冲channel

  1. 无缓冲的通道(unbuffered channel)
  2. 这种类型的通道要求发送goroutine和接收goroutine同时准备好,才能完成发送和接收操作。否则,通道会导致先执行发送或接收操作的 goroutine 阻塞等待。
package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan int, 0) //创建无缓冲的通道 c

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

	go func() {
		defer fmt.Println("子协程结束") //主协程结束时子协程还未结束,所以此句话没有打印出来
		for i := 0; i < 3; i++ {
			c <- i //子协程向管道写入后,将阻塞,主协程抢到cpu
			fmt.Printf("子协程正在运行[%d]: len(c)=%d, cap(c)=%d\n", i, len(c), cap(c))
		}
	}()

	time.Sleep(2 * time.Second) //延时2s,此时子协程将抢到cpu

	for i := 0; i < 3; i++ {
		num := <-c //从c中接收数据,并赋值给num
		fmt.Println("num = ", num)
	}

	fmt.Println("main协程结束")
}

缓冲channel

  1. 有缓冲的通道(buffered channel)
  2. 通道空时读阻塞,通道满时写阻塞
package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan int, 3) 
	fmt.Printf("len(c)=%d, cap(c)=%d\n", len(c), cap(c))

	go func() {
		defer fmt.Println("子协程结束")
		for i := 0; i < 3; i++ { //由于管道数量是3,向管道里连写3次数据
			c <- i
			fmt.Printf("子协程正在运行[%d]: len(c)=%d, cap(c)=%d\n", i, len(c), cap(c))
		}
	}()

	time.Sleep(2 * time.Second) //延时2s,子协程抢到cpu
	for i := 0; i < 3; i++ {
		num := <-c //从c中接收数据,并赋值给num
		fmt.Println("num = ", num)
	}
	fmt.Println("main协程结束")
}

关闭管道

  1. 结束range循环需要关闭channel;
  2. 关闭channel后,无法向channel 再发送数据(引发 panic 错误后导致接收立即返回零值);
  3. 关闭channel后,可以继续从channel接收数据;
  4. 对于nil channel,无论收发都会被阻塞。
package main
import (
    "fmt"
)

func main() {
    c := make(chan int)
    go func() {
        for i := 0; i < 5; i++ {
            c <- i
        }
        close(c)//把 close(c) 注释掉,会一直阻塞在 for data := range c 那一行,因为没有刻度的
    }()
    for data := range c {
        fmt.Println(data)
    }
    fmt.Println("Finished")
}

单向管道

  1. chan<- 表示数据进入管道
  2. <-chan 表示数据从管道出来
  3. 可以将 channel 隐式转换为单向队列,只收或只发,不能将单向 channel 转换为普通 channel:
c := make(chan int, 3)
var send chan<- int = c // send-only
var recv <-chan int = c // receive-only
send <- 1

同步

package main

import (
	"fmt"
	"time"
)

var channel = make(chan int) // 全局定义channel, 用来完成数据同步

func printer(s string) {
	for _, ch := range s {
		fmt.Printf("%c", ch)
		time.Sleep(300 * time.Millisecond)
	}
}

func person1() { // person1 先执行,中间sleep时会切换到person2,但person2取channel会阻塞,这期间person1又会抢回cpu
	printer("hello")
	channel <- 1
}
func person2() { // person2 后执行
	<-channel
	printer("wrold")
}

func main() {
	go person1()
	go person2()

	for {
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go 语言和 Java 语言在某些方面有相似之处,但也存在一些重要的区别。以下是 Go 语言和 Java 语言的一些对比: 1. 语法和易用性:Go 语言的语法相对简洁,更易于学习和上手,而 Java 语言的语法相对复杂一些。相比之下,Go 语言更注重简洁和可读性。 2. 并发编程:Go 语言天生支持并发编程,通过 goroutine 和 channel 提供了方便的并发模型。而在 Java 语言中,需要通过线程和锁等手段来进行并发编程。 3. 性能:在某些场景下,Go 语言的性能可能会优于 Java 语言。Go 语言的编译速度快,执行效率高,并且在并发处理方面表现出色。Java 语言则在大型企业级应用开发方面更常用。 4. 生态系统和库支持:Java 语言拥有非常庞大且成熟的生态系统和丰富的第三方库支持,可以满足各种应用场景的需求。而相对而言,Go 语言的生态系统还相对较小,但也在不断发展壮大。 5. 内存管理:Go 语言使用垃圾回收机制来管理内存,开发者无需手动管理内存,简化了代码的编写。Java 语言也有垃圾回收机制,但相对于 Go 语言,可能更加复杂。 6. 静态类型 vs 动态类型:Java 语言是静态类型语言,需要在编译时确定变量的类型。而 Go 语言是静态类型语言,但具有类型推导的特性,可以根据上下文自动推断变量的类型。 总体来说,Go 语言和 Java 语言都是强大的编程语言,各有优势和适用场景。选择使用哪种语言取决于具体的需求和项目要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值