golang入门笔记—channel

在这里插入图片描述

//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是随机进行匹配的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值