Golang题库(三)

同一个协程里面,对无缓冲channel同时发送和接收数据有什么问题

同一个协程里,不能对无缓冲channel同时发送和接收数据,如果这么做会直接报错死锁。

对于一个无缓冲的channel而言,只有不同的协程之间一方发送数据一方接受数据才不会阻塞。channel无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读到数据。

channel和锁的对比

  • Channel是用于处理协程中的数据通信问题的,通过编程逻辑设计,可以实现的效果。
  • Mutex是用于控制原子性操作数据安全性,通过加锁释放确保区间内数据只能有单一协程访问。数据一致性。
  • 两者的用途不同
  • 两者内存占用也不同

channel的应用场景

channel用于协程之间数据通信,根据设计能够实现多种功能。

任务超时与取消

通过在通道中传递信号,可以实现任务的超时和取消机制。例如,一个 goroutine 可以在执行耗时操作时启动一个定时器,如果操作在指定时间内未完成,可以通过通道发送取消信号给其他 goroutine,从而取消操作。

比如超时处理:

1
2
select {
case <-time.After(time.Second):

定时任务

1
2
select {
case <- time.Tick(time.Second)

事件发布与订阅(事件驱动编程)

通道可以用作发布者和订阅者之间的消息传递机制。发布者将事件发送到通道,订阅者从通道接收事件并进行相应的处理。这种模式可以用于实现观察者模式或消息队列等场景。

控制并发数

通道可以用于限制并发任务的数量,控制并发度。通过创建有缓冲的通道,可以限制通道中可以放入的元素数量,从而控制并发任务的数量。例如控制并发为5个协程:

1
2
3
4
5
6
7
8
ch := make(chan int, 5)
for _, url := range urls {
go func() {
ch <- 1
worker(url)
<- ch
}
}

数据流处理

通道在处理数据流时非常有用。一个 goroutine 可以负责生成数据,并将数据发送到通道中,而另一个或多个 goroutine 可以从通道中接收数据并进行处理,实现数据的流动和处理。

并发任务的协调

通道可以用于在不同的 goroutine 之间传递数据,实现并发任务的协调和通信。例如,一个主 goroutine 可以将任务分发给多个工作 goroutine,通过通道发送任务并接收结果。

多个 goroutine 的结果汇总

当有多个 goroutine 并行执行任务时,可以使用通道将它们的结果汇总。每个 goroutine 将结果发送到通道,然后另一个 goroutine 从通道中接收并处理这些结果。

线程安全的数据传递与共享

通道提供了一种线程安全的数据传递方式,避免了显式的锁操作。多个 goroutine 可以通过通道进行数据传递和共享,保证数据访问的原子性和一致性。

slice和array区别

在Go语言中,Slice(切片)和Array(数组)是两种不同的数据类型,它们之间有以下区别:

  1. 大小固定 vs. 大小可变:数组的长度是固定的,在声明时就需要指定其长度,并且长度不可变。而切片的长度是可变的,可以根据需要进行动态扩容或缩减。
  2. 值传递 vs. 引用传递:数组在赋值或传递给函数时是按值传递的,即会复制整个数组的内容。切片则是引用传递的,赋值或传递切片时只会复制切片的指针、长度和容量,并不会复制底层数据。
  3. 内存分配方式:数组在声明时会直接在内存中分配连续的空间来存储元素,因此数组的内存布局是连续的。切片则是建立在数组之上的动态数据结构,底层依赖于数组,并且可以自动进行内存扩容。
  4. 初始化方式:数组可以使用字面量或初始化表达式进行初始化,需要指定固定长度。切片可以通过使用字面量或通过 make() 函数进行初始化,并且可以根据需要动态改变长度。
  5. 传递性:数组作为函数参数传递时,会进行一次完整的复制,传递的是数组的副本。而切片作为函数参数传递时,只是传递了指向底层数组的指针、长度和容量,不会进行复制。
  6. 长度信息:数组的长度是固定的,可以通过 len() 函数获取数组的长度。切片则可以使用 len() 函数获取当前切片的长度,可以通过 cap() 函数获取切片的容量。

总的来说,数组适用于固定长度且不需要频繁扩容的情况,而切片则更加灵活,适用于需要动态改变长度或进行大量操作的场景。在实际开发中,切片更常用,因为它提供了更多的便利和功能,而数组则更适合特定需求的场景。