一.go关键字
1.概念
(1).通过关键字 go 来创建 goroutine
(2).所有的go函数都是并发执行的,谁先谁后并不能确定
(3).go函数是可以有结果声明的,但它们返回的结果值会在其执行完成后被丢弃。如果想把go函数的计算结果传递给其他go函数,将通过Channel来实现
2.例子
package main
import (
"fmt"
)
func Goroutine_simple_many_who() {
str := []string{"1111\n", "2222\n", "3333\n", "4444\n"}
for _, pr := range str {
go func() {
fmt.Print(pr)
}()
}
}
func Goroutine_simple_many_order() {
str := []string{"1111\n", "2222\n", "3333\n", "4444\n"}
for _, pr := range str {
go func(name string) {
fmt.Print(name)
}(pr)
}
}
func main() {
//并发的执行的5个go函数,打印的值都是4444。
//这是因为它们都是在for语句执行完之后才执行的。而pr在这时已经被赋值给了Mark
Goroutine_simple_many_who()
//发现都能打印出来,但顺序不定
//func使用参数name,每次pr被赋值的时候,对应的值都会被传递给name这个参数
//因此当go函数执行的时候,就是对应的数据
Goroutine_simple_many_order()
}
二.chan关键字(channel)
1、channel类型表示法:
(1).使用关键字chan
2、概念
(1).在同一时刻,仅有一个goroutine能向一个通道发送元素值,同时也仅有一个gorountine能从它那里接收元素值
(2).先进先出
(3).具有原子性,不可分割
(4).通道中每一个元素值都只能被某一个goroutine接收,已被接收会被立即删除
(5).从channel读数据,如果channel缓冲区为空或者没有缓冲区,当前goroutine会被阻塞。
向channel写数据,如果channel缓冲区已满或者没有缓冲区,当前goroutine会被阻塞
3、初始化
(1).声明
type chan_int chan int 或var chan_int chan int
(2)初始化
make(chan int,10)
4.slect配合使用
(1).select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收
(2).select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行
5.出让时间片段
runtime.Gosched函数
runtime.Gosched函数的作用是暂停调用他的Goroutine的运行,调用他的Goroutine会被重新置于Gorunnable状态,并被放入调度器可运行G队列中
6.注意事项
7.例子
package main
import (
"fmt"
"runtime"
)
//无缓冲
var chan_int_no_buffer chan int
//缓冲
var chan_int_buffer_str chan string
//缓冲结构体
var chan_int_buffer_struct chan person
//退出通道
var Chan_close chan bool
func Goroutine_channel_no_buffer() {
//初始化
chan_int_no_buffer = make(chan int)
go func() {
chan_int_no_buffer <- 2
fmt.Printf("发送数据chan_int_no_buffer\n")
}()
go func() {
value := <-chan_int_no_buffer
fmt.Printf("接收数据 chan_int_no_buffer: %d\n", value)
}()
time.Sleep(2 * time.Second)
}
func Goroutine_channel_buffer() {
chan_int_buffer_str = make(chan string, 2)
chan_number := []string{"1111", "2222", "3333", "4444", "5555", "6666"}
//1个接收者
go func() {
for {
if value, ok := <-chan_int_buffer_str; ok {
fmt.Println("Goroutine_channel_buffer接收数据完成:" + value + "\n")
} else {
fmt.Println("Goroutine_channel_buffer关闭:" + "\n")
break
}
}
}()
for _, number := range chan_number {
go func(num string) {
fmt.Println("Goroutine_channel_buffer开始发送数据:" + num + "\n")
chan_int_buffer_str <- num
}(number)
}
}
func Goroutine_channel_buffer_struct() {
chan_int_buffer_struct = make(chan person, 2)
chan_number := []person{
{
"LI",
"1111",
"23",
},
{
"Wang",
"2222",
"24",
},
}
//1个接收者
go func() {
for {
if value, ok := <-chan_int_buffer_struct; ok {
fmt.Println("chan_int_buffer_struct接收数据完成:" + value.Name + "--" + value.ID + "--" + value.Age + "\n")
} else {
fmt.Println("chan_int_buffer_struct关闭:" + "\n")
break
}
}
}()
for _, number := range chan_number {
go func(num person) {
fmt.Println("chan_int_buffer_struct开始发送数据:" + num.Name + "--" + num.ID + "--" + num.Age + "\n")
chan_int_buffer_struct <- num
}(number)
}
}
//select 多路复用
func Goroutine_channel_buffer_select() {
chan_int_buffer_struct = make(chan person, 2)
chan_int_buffer_str = make(chan string, 2)
chan_int_no_buffer = make(chan int)
Chan_close = make(chan bool)
chan_number := []person{
{
"LI",
"1111",
"23",
},
{
"Wang",
"2222",
"24",
},
}
chan_number_str := []string{"1111", "2222", "3333", "4444", "5555", "6666"}
for _, number := range chan_number {
go func(num person) {
fmt.Println("chan_int_buffer_struct开始发送数据:" + num.Name + "--" + num.ID + "--" + num.Age + "\n")
chan_int_buffer_struct <- num
}(number)
}
for _, number := range chan_number_str {
go func(num string) {
runtime.Gosched() //出让时间片段
fmt.Println("Goroutine_channel_buffer开始发送数据:" + num + "\n")
chan_int_buffer_str <- num
}(number)
}
go func() {
chan_int_no_buffer <- 2
fmt.Printf("发送数据chan_int_no_buffer\n")
}()
go func() {
defer close(chan_int_buffer_str)
defer close(chan_int_no_buffer)
defer close(chan_int_buffer_struct)
for {
select {
case str_tmp := <-chan_int_buffer_str:
fmt.Println("Goroutine_channel_buffer接收数据完成:" + str_tmp + "\n")
case struct_tmp := <-chan_int_buffer_struct:
fmt.Println("chan_int_buffer_struct接收数据完成:" + struct_tmp.Name + "--" + struct_tmp.ID + "--" + struct_tmp.Age + "\n")
case int_tmp := <-chan_int_no_buffer:
fmt.Printf("接收数据 chan_int_no_buffer: %d\n", int_tmp)
case <-Chan_close:
fmt.Printf("结束select\n")
return
}
}
}()
}
func main() {
//无缓冲
//Goroutine_channel_no_buffer()
//有缓冲
//Goroutine_channel_buffer()
//缓冲结构体
//Goroutine_channel_buffer_struct()
//select多路复用以及出让时间片段
Goroutine_channel_buffer_select()
time.Sleep(time.Duration(2) * time.Second)
close(Chan_close)
time.Sleep(time.Duration(1) * time.Second)
}
8.例子优化
1.上面例子未实现channel关闭以及CPU利用以及同步动作。
优化方案2sync.WaitGroup同步操作,3channel关闭
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
//无缓冲
var chan_int_no_buffer chan int
//缓冲
var chan_int_buffer_str chan string
//缓冲结构体
var chan_int_buffer_struct chan person
//退出通道
var Chan_close chan bool
//select 多路复用
//优化方案1.FAN模式优化时间使用.2sync.WaitGroup同步操作,3channel关闭
func Goroutine_channel_buffer_select_optimize(wg *sync.WaitGroup) {
chan_int_buffer_struct = make(chan person, 2)
chan_int_buffer_str = make(chan string, 2)
chan_int_no_buffer = make(chan int)
Chan_close = make(chan bool)
chan_number := []person{
{
"LI",
"1111",
"23",
},
{
"Wang",
"2222",
"24",
},
}
chan_number_str := []string{"1111", "2222", "3333", "4444", "5555", "6666"}
for _, number := range chan_number {
wg.Add(1)
go func(num person) {
fmt.Println("chan_int_buffer_struct开始发送数据:" + num.Name + "--" + num.ID + "--" + num.Age + "\n")
chan_int_buffer_struct <- num
}(number)
}
for _, number := range chan_number_str {
wg.Add(1)
go func(num string) {
runtime.Gosched() //出让时间片
fmt.Println("Goroutine_channel_buffer开始发送数据:" + num + "\n")
chan_int_buffer_str <- num
}(number)
}
go func() {
chan_int_no_buffer <- 2
wg.Add(1)
fmt.Printf("发送数据chan_int_no_buffer\n")
}()
go func() {
for {
select {
case str_tmp := <-chan_int_buffer_str:
fmt.Println("Goroutine_channel_buffer接收数据完成:" + str_tmp + "\n")
wg.Done()
case struct_tmp := <-chan_int_buffer_struct:
fmt.Println("chan_int_buffer_struct接收数据完成:" + struct_tmp.Name + "--" + struct_tmp.ID + "--" + struct_tmp.Age + "\n")
wg.Done()
case int_tmp := <-chan_int_no_buffer:
fmt.Printf("接收数据 chan_int_no_buffer: %d\n", int_tmp)
wg.Done()
case <-Chan_close:
fmt.Printf("结束select\n")
return
}
}
}()
}
func Finish() {
defer func() {
close(chan_int_buffer_str)
fmt.Println("关闭信道:" + "\n")
}()
defer close(chan_int_no_buffer)
defer close(chan_int_buffer_struct)
}
func main() {
//无缓冲
//Goroutine_channel_no_buffer()
//有缓冲
//Goroutine_channel_buffer()
//缓冲结构体
//Goroutine_channel_buffer_struct()
//select多路复用以及出让时间片段
var wg_struct sync.WaitGroup
Goroutine_channel_buffer_select_optimize(&wg_struct)
wg_struct.Wait()
close(mytools.Chan_close)
Finish()
}