1、启动go语言的协程

package main

import (
	"fmt"
	"runtime"
)

//runtime包

func main() {
	//runtime.Gosched() 用于让出cpu时间片,让出这段cpu的时间片,让调度器重新分配资源

	//写一个匿名函数
	s := "test"
	go func(s string) {
		for i :=0;i <2;i++ {
			fmt.Println(s)
		}
	}(s)

	for i :=0;i <2;i ++ {
		//如果代码跑到这里,调度器会把cpu资源释放出来,让调度器重新分配cpu资源,可以分配到子协程,也可以重新分配到主协程
		runtime.Gosched()
		fmt.Println("123")
	}
}

  

2、runtime.Goexit()方法。立即终止当前的协程

package main

import (
	"fmt"
	"runtime"
	"time"
)

//runtime.Goexit()   立即终止当前的协程
func main() {
	go func() {
		defer fmt.Println("A.defter")
		func () {
			defer fmt.Println("B.defter")
			//立即终止当前的协程,函数会走defer流程
			runtime.Goexit()
			fmt.Println("B")
		}()
		fmt.Println("A")
	}()
	for {
		time.Sleep(2 * time.Second)
	}
}

//不加runtime.Goexit()的结果
//B
//B.defter
//A
//A.defter

//加runtime.Goexit()的结果
//B.defter
//A.defter

  

3、runtime.GOMAXPROCS()表示go使用几个cpu执行代码

package main

import (
	"fmt"
	"runtime"
)

func main() {
	//runtime.GOMAXPROCS() 表示让go用几个cpu做后面的事情
	n := runtime.GOMAXPROCS(4)
	fmt.Printf("%T--->%p---%d\n",n,n,n)
	for {
		go fmt.Print("0")
		fmt.Print(1)
	}
}

  

 4、管道定义和创建管道

package main

import "fmt"

//go语言的协程运行在相同的地址空间,因此访问共享内存必须做好同步,处理好线程安全问题

//go语言的协程之间的通信通过协程间通信来共享内存,而不是共享内存来通信

//channel是一个引用类型,用于多个协程间通信,内部实现了同步,确保并发安全


//通道一般是结合协程一起使用


//如果通道中没有数据,后面你还去取数据,则会报错
//fatal error: all goroutines are asleep - deadlock!
func main() {
	//test45_1 := make(chan int) //定义一个无缓冲的通道

	//无缓冲的通道是值在接受数据前没有任何能力保存数据,只能有一个数据进入通道,进入通道后,该通道就会加锁,一直到这个数据被取出,锁才释放

	//无缓冲的通道有可能阻塞,如果我发送一个数据到通道,但是没有协程来取数据,则对于第一个协程就被阻塞

	//test45_2 := make(chan int,10)  //定义 一个有缓冲的通道


	//有缓冲的通道就是通道可以存储指定数量的数据,数据在里面也是有顺序的,但是如果缓冲的数量满了,这个通道也会是阻塞的

	//
	//test45_1 <- 10   //发送数据到通道
	//<- test45_1      //接受通道中的数据,并丢弃
	//x := <-test45_1 //从通道取值并赋值给x
	//x,ok := <-test45_1  //ok检查通道是否关闭或者是否为空


	//1、创建一个存放int类型的通道
	test45_1 := make(chan int)

	go func() {
		defer fmt.Println("子协程结束")
		fmt.Println("子协程正在运行")

		test45_1 <- 111
	}()
	//<- test45_1
	//主协程从通道中取数据
	x := <- test45_1
	fmt.Println(x)
	fmt.Println("主协程结束")
}

  

5、管道的缓冲

package main

import (
	"fmt"
	"time"
)

func main() {
	//无缓冲的通道,长度为0就可以了,有缓冲的通道,这里设置为非0就可以了
	test46_1 := make(chan int,0)

	//%P是打印内存地址,%T是打印变量的类型
	//fmt.Printf("长度:%d--->容量:%d---->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1)

	go func() {
		defer fmt.Printf("子协程结束")

		for i :=0;i < 3;i ++ {
			fmt.Println("子协程插入数据")
			test46_1 <- i
			//fmt.Printf("长度:%d--->容量:%d---->%P----%T",len(test46_1),cap(test46_1),test46_1,test46_1)

		}

	}()

	time.Sleep(2 * time.Second)
	for j :=0;j <3;j++ {
		fmt.Println("主协程取数据")
		num := <- test46_1
		fmt.Println(num)
	}
}

  

6、关闭管道和接受关闭管道的信号

package main

import "fmt"

//close()方法,关闭通道的意思

func main() {
	test47_1 := make(chan int,4)

	go func() {
		for i :=0;i < 10;i ++ {
			test47_1 <- i
		}
		//这个的意思关闭通道test47_1
		close(test47_1)
	}()

	//for的写法,遍历通道
	//for {
	//	//子协程关闭了通道,这里ok就可以接收到,这里就可以走到bread流程,ok这个参数表示通道是否关闭
	//	if data,ok := <- test47_1;ok {
	//		fmt.Println(data)
	//	}else {
	//		break
	//	}
	//}

	//range的写法,遍历通道
	for data := range test47_1 {
		fmt.Println(data)
	}
	fmt.Println("主协程结束")
}

  

7、只读管道和只写管道和生产者和消费者模型

package main

import (
	"fmt"
	"time"
)

//默认情况下,管道是双向的,既可以写入数据,也可以读出数据。go也可以定义单方向的管道,也就是说只发送数据,或者只写入数据

//可以把双向的管道转换为单向的管道,但是不能把单向的管道转换为双向的管道

//单方向的管道

func producter(out chan <- int)  {
	defer close(out)
	for i := 0;i < 10;i++ {
		out <- i
	}

}

func consumer(int <-chan int){
	for num := range int {
		fmt.Println(num)
	}
}
func main() {

	//1、定义管道
	//定义一个正常的管道
	//var test48_1 chan int

	//定义一个单向的只写的管道
	//var test48_2 chan <- float32

	//定义一个单向的只读的管道
	//var test48_3 <- chan int

	//2、转换管道

	//转换正常管道为只写或者只读的管道
	//定义一个正常的管道
	//test48_4 := make(chan int,3)

	//把一个正常的管道转换为一个只写的管道
	//var write_only chan <- int = test48_4

	//把一个正常的管道转换为一个只读的管道
	//var read_only <- chan int = test48_4



	test48_5 := make(chan int,4)

	//启动生产者
	go producter(test48_5)

	//启动消费者
	consumer(test48_5)

	time.Sleep(10 * time.Millisecond)
	fmt.Println("down")

}

  

 8、Timer定时器

package main

import (
	"fmt"
	"time"
)

//定时器

//time.NewTimer()。时间到了,只执行一次
//time.NewTicker(),周期性的执行

func main() {
	//1、创建一个定时器,2s后定时器会将一个时间保存到一个C
	test49_1 := time.NewTimer(2 * time.Second)

	//打印系统当前的时间

	t1 := time.Now()

	fmt.Printf("t1----->%v\n",t1)

	//从管道中取出C打印

	t2 := <- test49_1.C
	fmt.Printf("t2----->%v\n",t2)



	//2、证明timer只执行一次
	//test49_2 := time.NewTimer(4 * time.Second)
	//
	//for {
	//	c := <- test49_2.C
	//	fmt.Println(c)
	//}

	//3、通过timer实现一个延时的功能

	//方式1
	//time.Sleep(2 * time.Second)

	//方式2
	//test49_3 := time.NewTimer(2 * time.Second)

	//方式3

	//<-time.After(2 *time.Second)

	//4、停止定时器
	test49_4 := time.NewTimer(4 * time.Second)
	//子协程
	go func() {
		//这个意思是3s后才能取出来数据
		<- test49_4.C

		fmt.Println("定时器时间到了")
	}()

	//关闭定时器
	stop := test49_4.Stop()
	if stop {
		fmt.Println("定时器已经关闭")
	}

	//5、重置定时器
	test49_5 := time.NewTimer(4 * time.Second)
	//重置定时器为1s
	test49_5.Reset(1 * time.Second)

	for {

	}
	}

  

9、ticker定时器和关闭ticker定时器

 

package main

import (
	"fmt"
	"time"
)

//time.NewTicker(),定时器,响应多次

func main() {
	//创建一个定时器,间隔1s
	test50_1 := time.NewTicker(time.Second)
	i := 0
	go func() {
		for {
			c := <- test50_1.C
			fmt.Println(c)
			i ++
			fmt.Println(i)
		}
		}()


	for {

	}
}

  

10、select语句

package main

import (
	"fmt"
)

//go语言提供select关键字,用来监听通道上的数据流动,语法和switch类似,区别是select必须要求每个case语句里必须是一个IO操作

//如果都能匹配到,则随机选择一个通道去跑,select是比较随便的

func main() {
	//test51_1 := make(chan int,3)
	//select {
	//case <- test51_1:
	//	fmt.Println("jja")
	////如果从通道中可以读出数据,则执行这里
	//case test51_1 <- 1:
	//	fmt.Println("aa")
	////如果通道中北写入数据,则执行号这里
	//default:
	//	fmt.Println("hah")
	////如果上面都没成功,则执行这里
	//}


	test51_1 := make(chan int,1)
	test51_2 := make(chan string,1)

	go func() {
		//time.Sleep(2 * time.Second)
		test51_1 <- 1

	}()
	go func() {
		test51_2 <- "Hello World"
	}()

	select {
	case Value1:= <- test51_1:
		fmt.Println(Value1)
	case Value2 := <- test51_2:
		fmt.Println(Value2)
	}
	fmt.Println("结束")

}

  

11、协程同步锁

 

package main

import (
	"fmt"
	"sync"
	"time"
)

//go语言的协程同步锁,解决并发安全问题


//取钱的例子

type Account struct {
	money int
	flag sync.Mutex
}

func Check(a *Account)  {
	time.Sleep(1 * time.Second)
}

func (a *Account)SetAccount(n int)  {
	a.money = n
}

func (a *Account)GetAccount() (n int) {
	return a.money
}

func (a *Account) buy1(n int)  {
	a.flag.Lock()
	if a.money > n {
		Check(a)
		a.money -= n
	}
	a.flag.Unlock()
	fmt.Println(a.money)
}


func (a *Account) buy2(n int)  {
	a.flag.Lock()
	if a.money > n {
		Check(a)
		a.money -= n
	}
	a.flag.Unlock()
	fmt.Println(a.money)
}

func main() {
	var test52_1 Account
	test52_1.SetAccount(10)

	go test52_1.buy1(5)
	go test52_1.buy2(6)
	for {

	}
}

  

12、wait

我们自己实现wait

package main

import "fmt"
//Add() 计数加1
//Done() 计数减1
//Wait() 主函数调用
func main() {
	test53_1 := make(chan int,2)
	count := 2
	go func() {
		fmt.Println("子协程1")
		test53_1 <- 1
	}()
	go func() {
		fmt.Println("子协程2")
		test53_1 <- 2
	}()

	for range test53_1 {
		count --
		if count == 0 {
			fmt.Println("所有的子协程都已经结束")
			close(test53_1)
		}
	}
}

  

go语言为我们实现wait

package main

import (
	"fmt"
	"sync"
)
//Add() 计数加1
//Done() 计数减1
//Wait() 主函数调用
func main() {

	var wait_group sync.WaitGroup

	//这里就是子协程的个数
	wait_group.Add(2)
	//test54_1 := make(chan int,2)

	go func() {
		fmt.Println("子协程1")
		wait_group.Done()
	}()
	go func() {
		fmt.Println("子协程2")
		wait_group.Done()
	}()


	wait_group.Wait()
	//close(test53_1)
	fmt.Println("所有的子协程都结束")

}

  

posted on 2019-05-23 22:58  bainianminguo  阅读(281)  评论(0编辑  收藏  举报