创建协程:

package main

import "fmt"
import "time"

func NewTask() {
	for {
		fmt.Println("This is a newTask")
		time.Sleep(time.Second)
	}
}

func main() {

	go NewTask() // 新建一个协程,新建一个任务

	for {
		fmt.Println("This is gorutine")
		time.Sleep(time.Second)
	}
}

主协程退出,子协程也会退出:

package main

import (
	"fmt"
	"time"
)

func main() {
	go func() {
		i := 0
		for {
			i++
			fmt.Println("子协程 i = ", i)
			time.Sleep(time.Second)
		}
	}()

	i := 0
	for {
		i++
		fmt.Println("主协程 i = ", i)
		time.Sleep(time.Second)
		if i == 2 {
			break
		}
	}
}

主协程先退出子协程还没来得及调用:

package main

import (
	"fmt"
	"time"
)

func main() {

	// 主协程结束了,子协程未被调用也跟着退出了
	go func() {
		i := 0
		for {
			i++
			fmt.Println(i)
			time.Sleep(time.Second)
		}
	}()
}

runtime.Gosched 让子协程先执行:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(i)
		}
	}()

	// 让出时间片,让子协程先执行
	runtime.Gosched()
	fmt.Println("main")
}

runtime.Goexit 结束子协程:

package main

import (
	"fmt"
	"runtime"
)

func Demo() {
	fmt.Println("aaaa")
	runtime.Goexit() // 结束子协程
	fmt.Println("bbbb")
}
func main() {
	go func() {
		fmt.Println("xxx")
		Demo()
		fmt.Println("ccc")
	}()

	// 不让主协程结束
	for {
	}
}

runtime.GOMAXPROCS 指定运行的核心数:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	// 指定使用的CPU核心数,返回值为计算机的核心数
	n := runtime.GOMAXPROCS(1) // 1表示当前使用的核心数
	fmt.Println("n = ", n)
	
	// 当指定不同的核心数时可以看到子协程和主协程切换的频率是不同的
	for {
		go fmt.Print(1)
		fmt.Print(0)
	}
}

资源竞争:

package main

import (
	"fmt"
	"time"
)

// 按字符打印
func Printer(str string) {
	for _, data := range str {
		fmt.Printf("%c", data)
		time.Sleep(time.Second)
	}
	fmt.Printf("\n")
}

func Person1() {
	Printer("hello")
}

func Person2() {
	Printer("world")
}

func main() {
	// 这样会出现资源竞争
	go Person1()
	go Person2()

	for {
	}
}

channel 通道:通过管道解决资源竞争问题

package main

import (
	"fmt"
	"time"
)

var ch = make(chan int)

// 按字符打印
func Printer(str string) {
	for _, data := range str {
		fmt.Printf("%c", data)
		time.Sleep(time.Second)
	}
	fmt.Printf("\n")
}

func Person1() {
	Printer("hello")
	ch <- 666 // 给管道发送数据
}

func Person2() {
	<-ch // 从管道接收数据,无数据就会阻塞
	Printer("world")
}

func main() {
	// 这样会出现资源竞争
	go Person1()
	go Person2()

	for {
	}
}

channel:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan string) // 创建管道

	go func() {
		fmt.Println("111")
		time.Sleep(time.Second)
		fmt.Println("222")
		time.Sleep(time.Second)
		ch <- "子协程结束"
	}()
	str := <-ch //当检测到数据后主协程继续执行
	fmt.Println(str)
	defer fmt.Println("主协程结束")
}

无缓冲channel:

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 0) // 0 表示无缓冲

	go func() {
		fmt.Println("aaa")
		ch <- 1 // 无缓冲的channel只有当里面的数据被读取才会往下执行
		fmt.Println("bbb")
		ch <- 2
		fmt.Println("ccc")
		ch <- 3
	}()

	time.Sleep(2 * time.Second) // 只要未读channel中的数据子协程就会阻塞

	num := <-ch
	fmt.Println("num = ", num)
	num = <-ch
	fmt.Println("num = ", num)
	num = <-ch
	fmt.Println("num = ", num)
}

有缓冲的channel:channel 容量未满之前不会出现阻塞

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int, 3) // 缓冲长度为3,没有容量存一个,有容量=容量+1
	fmt.Printf("len(ch) = %d,cap(ch) = %d\n", len(ch), cap(ch))

	go func() {
		for i := 0; i < 10; i++ {
			ch <- i
			fmt.Printf("len(ch) = %d,cap(ch) = %d\n", len(ch), cap(ch))
		}
	}()

	var num int
	for i := 0; i < 10; i++ {
		num = <-ch
		fmt.Printf("len(ch) = %d,cap(ch) = %d,num = %d\n", len(ch), cap(ch), num)
	}
}

关闭channel:

channel不需要进程去关闭除非确实没有数据可以发送了。

关闭后再写数据就会引发panic错误。

关闭channel后还可以继续接受channel的数据。

package main

import (
	"fmt"
)

func main() {
	ch := make(chan int) //无缓冲channel

	go func() {
		for i := 0; i < 10; i++ {
			ch <- i // 子线程每写一个下面的主线程就取一个
		}
		// 不需要写数据时就关闭channel
		close(ch)
	}()

	for {
		// 如果ok为true 说明管道没有关闭
		if num, ok := <-ch; ok == true {
			fmt.Println("num = ", num)
		} else {
			break // 当关闭管道时就跳出循环
		}
	}

	// 这个方法也可以遍历管道中的数据
	// for num := range ch {
	// 	fmt.Println(num)
	// }
}

单向cannel:

package main

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

	var writeCh chan<- int = ch //只能写,不能读
	var readCh <-chan int = ch  //只能读,不能写

	writeCh <- 666 // 写
	<-readCh       //读
}

单向channel的应用:可以当做队列使用

package main

import (
	"fmt"
)

// 生产者
func producer(ch chan<- int) {
	for i := 0; i < 10; i++ {
		ch <- i
	}
	close(ch)
}

// 消费者
func consumer(ch <-chan int) {
	for num := range ch {
		fmt.Println(num)
	}
}

func main() {
	ch := make(chan int)
	go producer(ch)
	consumer(ch)
}