当前位置:   article > 正文

golang的channel探索

golang的channel探索

1、channel是什么?

管道或者是通道。字面意思也就是说是传输的通道或者是管道。
在 Go 语言中,channel 的关键字chan数据流向的表现方式为 <-
分为两种模式:
双向– 表现形式为:chan T,即双向通道。
单向– 表现形式有两种。分别是:chan <- T表示只允许发送的通道,T <- chan表示只允许接收的通道。
除此之外,channel分为缓冲通道无缓冲通道

// 无缓冲
ch1 := make(chan int)

// 缓冲区为 3
ch2 := make(chan int, 3)
  • 1
  • 2
  • 3
  • 4
  • 5

2、无缓冲channel

缓冲区大小默认为0。
在Go语言中,无缓冲的channel是一种在发送和接收操作之间同步进行的通道。无缓冲channel保证了数据的传递几乎是即时的,发送操作会阻塞,直到另一端的goroutine执行接收操作,反之亦然。这种特性使得无缓冲channel成为goroutine之间同步操作和通信的理想选择。#### 如何创建?

ch := make(chan int)
  • 1
如何使用?
var ch = make(chan string)
	go func() {
		ch <- "包子"
	}()

	msg := <-ch
	fmt.Println(msg)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在上面的代码中,发送操作在另一个goroutine中执行,它会阻塞,直到主goroutine执行接收操作。

特性是什么?

无缓冲channel的一个关键特性是它们在发送和接收数据时提供了同步保证
当数据从一个goroutine通过无缓冲channel发送到另一个goroutine时,发送者goroutine会阻塞,直到接收者goroutine接收了数据,这确保了在两个goroutine之间的数据交换是同步的。

使用场景
  • 需要确保在数据处理过程中两个goroutine能够同步操作时。
  • 用来通知一个goroutine另一个goroutine的事件已经发生,比如任务完成或是需要停止执行
注意事项

会发生死锁的两种情况:

  • 没有goroutine接收发送过来的数据
  • 没有goroutine发送数据

3、有缓冲channel

和无缓冲相比,多了一个缓冲区域
无缓冲channel用来同步,有缓冲的channel用来异步
在Go语言中,有缓冲的channel允许在阻塞发送和接收操作之前存储一个固定数量的值。这种类型的channel是异步的:只有在缓冲区满时发送操作才会阻塞,只有在缓冲区空时接收操作才会阻塞

如何使用?
  • 当向有缓冲channel发送数据时,如果缓冲区未满,发送操作就会立即完成,并且发送goroutine可以继续执行不会阻塞。如果缓冲区已满,发送操作将会阻塞,直到有空间可用。
  • 从有缓冲channel接收数据时,如果缓冲区中有数据,接收操作会立即提取数据并继续执行。如果缓冲区为空,接收操作将会阻塞,直到有数据可读。
应用场景是什么?
  • 解耦生产者和消费者的处理速度:当生产者和消费者处理数据的速率不一致时,有缓冲的channel可以作为中间存储,减少直接的依赖
  • 流量控制通过限制缓冲区的大小,可以在一定程度上控制程序的内存使用,防止因为生产速度远大于消费速度而导致的内存溢出
  • 批量处理:有时,等待直到有足够的数据积累在缓冲区中之后再批量处理,可以提高处理效率。
注意事项
  • 缓冲区大小要合适。太小会导致频繁阻塞,太大会增加内存使用。甚至在生产者速度远大于消费者速度时导致内存泄漏
  • 即使channel是有缓冲的,也应避免在没有接收方时向channel发送数据,这可能会导致发送goroutine永久阻塞,从而造成goroutine泄漏。

4、如何判断goroutine是否关闭?

在Go语言中,并没有内置的方法去检测是否关闭
有3种模式可以间接地帮助理解goroutine是否已经完成了它的执行任务:

使用sync.WaitGroup
var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		// goroutine完成时调用
		defer wg.Done()
		// 执行任务
	}()

	// 等待所有goroutine全部结束(每个都调用done)
	wg.Wait()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

当wait返回时,表示相关的goroutine已经全部完成了。

使用channel
// 根据Go规范,空结构体不分配内存也就是说不占用空间
// 只是一个信号,没有其他意义
done := make(chan struct{})

	// 启动一个goroutine等待信号
	go func() {
		<-done // 等待信号,不关心传递的数据
		fmt.Println("Received signal, exiting.")
	}()

	// 发送信号
	close(done)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
使用context

如果你的goroutine是响应取消信号而结束的,那么可以通过检查context的状态来判断goroutine是否已经结束。

ctx, cancel := context.WithCancel(context.Background())

	go func() {
		// 等待取消信号
		<-ctx.Done()

		// 清理并退出
	}()

	// 发出取消信号
	cancel()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这种情况下,当cancel被调用时,依赖于这个context的所有goroutine将开始执行退出流程。

5、如何优雅的关闭goroutine?

  • 使用channel发送退出信号
done := make(chan struct{})

	go func() {
		for{
			select {
			//等待退出信号
			case <-done:
				// 收到信号,退出goroutine
				return
			default:
				// 正常执行任务
			}
		}
	}()

	// 当需要goroutine结束时,关闭channel 并广播给其他goroutine
	close(done)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 使用context包控制多个goroutine

如果多个goroutine使用了同一个context,context包提供了一个优雅的解决方案。你可以创建一个context,并在需要停止goroutine时取消它。

ctx, cancel := context.WithCancel(context.Background())

	go func() {
		for {
			select {
			//检测到取消信号
			case <-ctx.Done():
				// 退出goroutine
				return
			default:
				// 正常执行任务
			}
		}
	}()

	//当需要停止goroutine时,调用cancel通知使用该context的所有goroutine停止
	cancel()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 使用sync.WaitGroup等待goroutine完成优雅关闭
var wg sync.WaitGroup
	ctx, cancel := context.WithCancel(context.Background())

	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			select {
			//检测到取消信号
			case <-ctx.Done():
				// 退出goroutine
				return
			default:
				// 正常执行任务
			}
		}
	}()

	//通知使用该context的所有goroutine停止
	cancel()
	// 等待所有goroutine安全退出
	wg.Wait()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/193318
推荐阅读
相关标签
  

闽ICP备14008679号