//channel
//var b chan <类型>
//通道必须用make函数初始化才能使用
//通道的操作
//1.发送:ch1<-1
//2.接收:x:=<-ch1
//3.关闭:close()
package main
import (
"fmt"
"sync"
)
var a []int
var b chan int //需要指定通道中元素的类型
var wg sync.WaitGroup
func noBufChannel() {
b = make(chan int) //为通道分配内存,带缓冲区
wg.Add(1)
go func() {
defer wg.Done()
x := <-b
fmt.Println("后台goroutine从通道b中取到了", x)
}()
b <- 10
fmt.Println("10发送到通道b中了...")
wg.Wait()
close(b)
}
func BufChannel() {
b = make(chan int, 1) //为通道分配内存,不带缓冲区
wg.Add(1)
b <- 10 //因为缓冲区为1,所以只能放一个数据
fmt.Println("10发送到通道b中了...")
wg.Wait()
close(b)
}
func main() {
noBufChannel()
}
package main
//channel练习
//1.启动一个goroutine,生成100个数发送到ch1
//2.启动一个goroutine,从ch1中取值,计算其平方放到channel2中
//3.在main中,从ch2中取值
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var once sync.Once
func f1(ch1 chan int) {
defer wg.Done()
for i := 0; i < 100; i++ {
ch1 <- i
}
close(ch1)
}
func f2(ch1, ch2 chan int) {
defer wg.Done()
for {
x, ok := <-ch1 //ch1通道关闭后ok为false
if !ok {
break
}
ch2 <- x * x
}
once.Do(func() { close(ch2) }) //锁,确保某个操作只执行一次
}
func main() {
a := make(chan int, 50) //一边放一边读,所以可以小于100
b := make(chan int, 100)
wg.Add(2)
go f1(a)
go f2(a, b)
go f2(a, b)
wg.Wait()
for ret := range b {
fmt.Println(ret)
}
}
//单向通道
func f1(ch1 chan<- int){ //只能发送的通道类型
defer wg.Done()
for i:=0;i<100;i++{
ch1<-i
}
close(ch1)
}
func f2(ch1 chan<- int,ch2 <-chan int) { //只能发送和只能接受通道定义
defer wg.Done()
for {
x, ok := <-ch1
if !ok {
break
}
ch2 <- x * x
}
close(ch1)
}
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
/*
使用goroutine和channel实现一个计算int64随机数各位数和的程序
1.开启一个goroutine循环生成int64类型的随机数,发送到jobChan
2.开启24个goroutine从jobChan中取出随机数计算各位数的和,将结果发送到resultChan
3.主goroutine从resultChan取出结果并打印到终端输出
*/
type job struct {
x int64
}
type result struct {
job *job
result int64
}
var jobChan = make(chan *job, 100)
var resultChan = make(chan *result, 100)
var wg sync.WaitGroup
func zhoulin(z1 <-chan *job) {
defer wg.Done()
//循环生成int64类型的随机数,发送到jobChan
for {
x := rand.Int63()
newJob := &job{
value: x,
}
z1 <- newJob
time.Sleep(time.Second * 500)
}
}
func baodelu(z1 <-chan *job, resultChan chan<- *result) {
defer wg.Done()
for {
job := <-z1
sum := int64(0)
n := job.value
for n > 0 {
sum += n % 10
n = n / 10
}
newResult := &result{
job: job,
result: sum,
}
resultChan <- newResult
}
}
func main() {
wg.Add(1)
go zhoulin(jobChan)
wg.Add(24)
for i := 0; i < 24; i++ {
go baodelu(jobChan, resultChan)
}
for result := range resultChan {
fmt.Printf("value:%d sum:%d\n", result.job.value, result.result)
}
wg.Wait()
}
for{
data,ok:=<-ch1
data,ok:=<-ch2
//这种方式取通道并不是随机的,而是先尝试取ch1,再尝试取ch2
}
select{
case<-ch1:
...
case data:=<-ch2:
...
case ch3<-data
...
default:
默认操作
}//select随机选取
func main(){
ch:=make(chan int,1)
for i:=0;i<10;i++{
select{
case x:=<-ch:
fmt.Println(x)
case ch<-i:
}
}
}
使用通道传递通道
package main
import "fmt"
var counter = func(n int) chan<- chan<- int {
requests := make(chan chan<- int)
go func() {
for request := range requests {
if request == nil {
n++
} else {
request <- n
}
}
}()
return requests
}(0)
func main() {
increase100 := func(done chan<- struct{}) {
for i := 0; i < 100; i++ {
counter <- nil
}
done <- struct{}{}
}
done := make(chan struct{})
go increase100(done)
go increase100(done)
<-done
<-done
request := make(chan int, 1)
counter <- request
fmt.Println(<-request)
}
Select的用法
select{
case 1:
case 2:
default:
}
在运行select时,程序遍历每一个case。当有一个case满足条件时,程序退出select。若所有case都未命中,则一直循环扫描,直到匹配中,这样容易会产生死锁。
避免产生死锁的方法:
1.在编写select程序时,一定带上default默认分支,即使default没有任何代码
2.一定有case命中
select-case的重要特点:select的随机性,switch-case中,扫描是顺序进行的,从上往下依次匹配,但是在select-case中,case是随机进行匹配的。