Go-chan 那些事

本文通过多个 Go 语言代码示例,详细讲解了通道(channel)的使用,包括无缓存通道和有缓存通道的发送与接收操作,以及在满载和空载情况下的阻塞现象。同时,还探讨了 `select` 语句的工作原理,包括有 default 和无 default 的行为差异,并展示了如何利用通道进行并发控制。最后,文章提到了通道关闭后的读写规则以及单向通道的应用,强调了它们在并发安全中的作用。
摘要由CSDN通过智能技术生成
  • 通道中没有数据, 接收数据会阻塞, 可以用第二个参数解决
  • 发送超过通道容量会阻塞
  • select 没有 default 会阻塞, 有 default 不会阻塞
  • select 语句最多只会有一个 case 命中
  • 通道关闭了, 可以收数据, 不可以发数据

上代码, 自己品:

package main

import "fmt"

func main() {
	ch := make(chan int) // 无缓存通道

	// 阻塞在发送语句
	ch <- 2 // fatal error: all goroutines are asleep - deadlock!
	ele := <-ch
	fmt.Println(ele)
}

package main

import "fmt"

func main() {
	ch := make(chan int) // 无缓存通道

	go func() {
		ch <- 2
	}()
	ele := <-ch
	fmt.Println(ele) // 2
}

package main

import "fmt"

func main() {
	ch := make(chan int) // 无缓存通道

	// 阻塞在接收语句
	ele := <-ch // fatal error: all goroutines are asleep - deadlock!
	fmt.Println(ele)
	go func() {
		ch <- 2
	}()
}

package main

import "fmt"

func main() {
	ch := make(chan int) // 无缓存通道

	i := 2

	go func() {
		// 通道内的是 i 的副本
		ch <- i
		i = 1
	}()
	ele := <-ch
	fmt.Println(ele) // 2
}

package main

import "fmt"

func main() {
	ch := make(chan *int) // 无缓存通道

	i := 2
	j := &i
	fmt.Printf("j (%v --> %v) = %d\n", &j, j, *j) // j (0xc000122018 --> 0xc000128008) = 2

	go func() {
		// 通道内的是指针 j 的副本
		ch <- j
		*j = 1
	}()
	ele := <-ch
	fmt.Printf("ele (%v --> %v) = %d\n", &ele, ele, *ele) // ele (0xc000122028 --> 0xc000128008) = 1
}

package main

import "fmt"

func main() {
	// FIFO
	ch := make(chan int, 2) // 有缓存通道

	ch <- 2
	ch <- 1

	ele := <-ch
	fmt.Println(ele) // 2

	ele = <-ch
	fmt.Println(ele) // 1

	ch <- 3
	ele = <-ch
	fmt.Println(ele) // 3

	ch <- 4
}

package main

import "fmt"

func main() {
	// FIFO
	ch := make(chan int, 2) // 有缓存通道

	ele := <-ch // fatal error: all goroutines are asleep - deadlock!
	fmt.Println(ele)

}

package main

import "fmt"

func main() {
	// FIFO
	ch := make(chan int, 2) // 有缓存通道

	ch <- 2
	ch <- 1
	ch <- 3 // fatal error: all goroutines are asleep - deadlock!

	ele := <-ch
	fmt.Println(ele)

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)

	ch1 <- "chan 1"

	select {
	case ele := <-ch1:
		fmt.Println(ele) // chan 1
	}

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)

	select {
	// 阻塞在接收语句
	case ele := <-ch1: // fatal error: all goroutines are asleep - deadlock!
		fmt.Println(ele)
	}

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)

	ch1 <- "chan 1"

	select {
	case ele := <-ch1:
		fmt.Println(ele) // chan 1
	default:
		fmt.Println("Default")
	}

}
package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)

	select {
	case ele := <-ch1:
		fmt.Println(ele)
	default:
		fmt.Println("Default") // Default
	}

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)
	ch2 := make(chan string, 1)

	ch1 <- "chan 1"
	ch2 <- "chan 2"

	select {
	case ele := <-ch1:
		fmt.Println(ele) // chan 1
	case ele := <-ch2:
		fmt.Println(ele)
	}

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)
	ch2 := make(chan string, 1)

	ch1 <- "chan 1"
	ch2 <- "chan 2"

	select {
	case ele := <-ch2:
		fmt.Println(ele) // chan 2
	case ele := <-ch1:
		fmt.Println(ele)
	}

}

package main

import "fmt"

func main() {
	ch1 := make(chan string, 1)
	ch2 := make(chan string, 1)

	select { // fatal error: all goroutines are asleep - deadlock!
	case ele := <-ch2:
		fmt.Println(ele) // chan 2
	case ele := <-ch1:
		fmt.Println(ele)
	}

}

package main

import "fmt"

func send(ch chan<- string) {
	ch <- "send"
	// 不允许接收 ch 中的数据
	//<-ch // Invalid operation: <-ch (receive from send-only type chan<- string)
}

func receive() <-chan string {
	ch := make(chan string, 1)
	ch <- "receive"
	return ch
}

func print(ch <-chan string) {
	fmt.Printf("print: %s\n", <-ch)
}

// 单向通道可以起到约束的作用
func main() {
	ch := make(chan string, 1)
	send(ch)
	print(ch) // print: send

	ch1 := receive()
	ele := <-ch1
	fmt.Println(ele) // receive
	// 不允许向 ch1 中发送数据
	//ch1 <- "other" // Invalid operation: ch1 <- "other" (send to receive-only type <-chan string)

}

package main

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

	close(ch)

	ch <- 2 // panic: send on closed channel

}

package main

import "fmt"

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

	close(ch)

	ele := <-ch
	fmt.Println(ele) // 0

}

package main

import "fmt"

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

	close(ch)

	ele, ok := <-ch
	fmt.Println(ele, ok) // 0 false

}

package main

import "fmt"

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

	//close(ch)

	ele, ok := <-ch // fatal error: all goroutines are asleep - deadlock!
	fmt.Println(ele, ok)

}

package main

import "fmt"

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

	ch <- 2

	close(ch)

	ele, ok := <-ch
	fmt.Println(ele, ok) // 2 true

	ele, ok = <-ch
	fmt.Println(ele, ok) // 0 false
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值