Go语言中的并发

并发,并行,串行 协程 概念

并发多个线程交替执行
并行 两个程序同时运行,多核多cpu 不一定快,如果两个代码要通信第一个线程要拿到第二个的结果必须等第二个线程把结果返回,通信开销大
串行 按部就班从上到下顺序执行
协程俗称轻量级的线程,协程调用完函数返回一个接口
Goroutine如果main的Goroutine终止了,程序将被终止,而其他Goroutine将不会运行

Goroutine

func main() {
	//获取goroot目录
	fmt.Println(runtime.GOROOT())
	fmt.Println(runtime.GOOS)
	fmt.Println(runtime.NumCPU())

	//go调度
	go func() {
		for i := 0; i < 100; i++ {
			fmt.Println("goroutine", i)
		}
	}()
	for i := 0; i < 100; i++ {
		//让时间片,让别人先执行
		runtime.Gosched()
		fmt.Println("main", i)

	}
}

Gorotine调度与终止

func main() {
	go func() {
		fmt.Println("start")
		text()
		fmt.Println("end")
	}()
	time.Sleep(time.Second * 2)
}
func text() {
	defer fmt.Println("test defer")
	//return 终止函数
	//终止协程	runtime.Goexit()

	fmt.Println("test")
}

临界资源安全问题

// 在并发编程中对临界资源处理不当,往往导致数据不一致的问题
func main() {

	a := 1
	go func() {
		a = 2
		fmt.Println("goroutine,a=", a)
	}()
	
	a = 3
	time.Sleep(time.Second * 2)
	fmt.Println("main,a=", a)

}

在这里插入图片描述

Mutex锁和 Waitgroup

var mutex sync.Mutex

var ticket int = 10

var wg1 sync.WaitGroup

func main() {
	wg1.Add(4)

	go saleTickets("售票口1")
	go saleTickets("售票口2")
	go saleTickets("售票口3")
	go saleTickets("售票口4")
	wg1.Wait()
}

//售票函数

func saleTickets(name string) {
	defer wg1.Done()
	for {
		//检查之前上锁
		mutex.Lock()
		if ticket > 0 {
			fmt.Println(name, "剩余票数", ticket)
			ticket--
		} else {
			mutex.Unlock()
			fmt.Println("票卖光了")
			break
		}
		mutex.Unlock()
	}
}

channel通道讲解

func main() {
	//定义一个bool类型的通道
	var ch chan bool
	ch = make(chan bool)

	go func() {
		for i := 0; i < i; i++ {
			fmt.Println(i)
		}
		ch <- true
	}()
	//读取通道中的数据
	data := <-ch
	fmt.Println("读取到通道中的信息,ch=", data)
}

关闭通道

func main() {

	ch := make(chan int)

	go test3(ch)
	//通道中读数据
	for {
		//time.Sleep(time.Second)
		v, ok := <-ch
		if !ok {
			fmt.Println("数据读取完毕,通道已经关闭 ok=", ok)
			break
		}
		fmt.Println("通道中读取的数据", v)
	}
	//狂总推荐用for-range
	//for v := range ch {
	//	fmt.Println("通道中读取的数据", v)
	//}

}
func test3(ch chan int) {
	for i := 0; i < 10; i++ {
		ch <- i
	}
	close(ch)
}

缓冲通道

func main() {

	ch1 := make(chan int)
	fmt.Println(len(ch1), cap(ch1))
	ch2 := make(chan int, 5)
	fmt.Println(len(ch2), cap(ch2))
	ch2 <- 2
	fmt.Println(len(ch2), cap(ch2))

	ch3 := make(chan string, 4)
	go test4(ch3)
	for v := range ch3 {
		time.Sleep(time.Second)
		fmt.Println(v)
	}

}

func test4(ch chan string) {
	for i := 0; i < 10; i++ {
		ch <- "test" + strconv.Itoa(i)
		fmt.Println("向缓冲区写入的数据", "test"+strconv.Itoa(i))
	}
	close(ch)
}
0 0
0 5
1 5
向缓冲区写入的数据 test0
向缓冲区写入的数据 test1
向缓冲区写入的数据 test2
向缓冲区写入的数据 test3
向缓冲区写入的数据 test4
test0
向缓冲区写入的数据 test5
test1
向缓冲区写入的数据 test6
test2
向缓冲区写入的数据 test7
test3
向缓冲区写入的数据 test8
test4
向缓冲区写入的数据 test9
test5
test6
test7
test8
test9

定向通道

func main() {
	//ch1 := make(chan<- int)
	//ch1 <- 200
	//temp := <-ch1 //cannot receive from send-only channel ch1 (variable of type chan<- int)
	//ch2 := make(<-chan int)
	//ch2 <- 200  //cannot send to receive-only channel ch2 (variable of type <-chan int)
	ch1 := make(chan int)
	go writeOnly(ch1)
	go readOnly(ch1)
	time.Sleep(time.Second)
}

// 只写通道
func writeOnly(ch chan<- int) {
	ch <- 100
}
func readOnly(ch <-chan int) {
	data := <-ch
	fmt.Println(data)
}

Select 随机选择通道中的数据

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go func() {
		time.Sleep(time.Second)
		ch1 <- 100
	}()
	go func() {
		time.Sleep(time.Second)
		ch2 <- 200
	}()
	select {
	case num1 := <-ch1:
		fmt.Println("ch1", num1)
	case num2 := <-ch2:
		fmt.Println("ch2", num2)
		//default:
		//fmt.Println("没有匹配到")

定时器

func main() {
	//创建一个定时器
	timer := time.NewTimer(3 * time.Second)
	fmt.Println(time.Now())
	//获取定时器的通道
	timerChan := timer.C
	//把定时器中的数据读出来
	fmt.Println(<-timerChan)
	fmt.Println("-------------------")
	//怎么手动关掉定时器

	timer2 := time.NewTimer(5 * time.Second)
	go func() {
		<-timer2.C //5s
		fmt.Println("子goroutine end")
	}()
	time.Sleep(time.Second * 2)
	stop := timer2.Stop()
	if stop {
		fmt.Println("timer2停止了")
	}
}

定时器第二个案例在指定时间触发函数执行

func main() {
	timeChan := time.After(time.Second * 3)
	fmt.Println(time.Now())
	chantime := <-timeChan
	fmt.Println(chantime)
	//在指定时间触发这个函数执行,备份
	time.AfterFunc(time.Second*3, test10)
	time.Sleep(time.Second * 5)
}
func test10() {
	fmt.Println("aaaaaa")
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值