其他分享
首页 > 其他分享> > Goroutine

Goroutine

作者:互联网

Goroutine

优雅地等子协程结束

package main

import (
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func Add(a int) int {
	defer wg.Done()
	fmt.Printf("num: %d\n", a)
	return a 
}

func main() {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go Add(i)
	}
	wg.Wait()
}

// 写法二
package main

import "sync"

func main() {
	wg := sync.WaitGroup{}
	wg.Add(10) // 加10
	for i := 0; i < 10; i++ {
		go func(a, b int) {
			defer wg.Done() // 减1
		}(i, i+1)
	}
	wg.Wait() // 等待
}

// 闭包情况一
func main() {
	wg := sync.WaitGroup{}
	wg.Add(10) // 加10
	for i := 0; i < 10; i++ {
		go func(a int) {
			defer wg.Done() // 减1
			// do something
			fmt.Println(a)
		}(i)
	}
	wg.Wait()
}
// $go run main.go
// 9
// 8
// 4
// 5
// 0
// 2
// 6
// 7
// 1
// 3

// 闭包情况二
func main() {
	wg := sync.WaitGroup{}
	wg.Add(10) // 加10
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done() // 减1
			// do something
			fmt.Println(i)
		}()
	}
	wg.Wait()
}
// $go run main.go
// 10
// 2
// 10
// 10
// 10
// 10
// 10
// 10
// 3
// 10

捕获子协程的panic

defer

recover恢复

不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存

chan struct{}

关闭channel

同步channel

// 示例
package main

import (
	"fmt"
	"time"
)

var ch = make(chan int)

func consumer(ch chan int) {
	for {
		v := <-ch // 阻塞
		fmt.Printf("取出:%d\n", v)
	}
}

func main() {
	go consumer(ch)
	ch <- 5
	time.Sleep(1 * time.Second)
}

// go run .\async_channel.go
// 取出:5
// 异常示例
package main

import (
	"fmt"
	"time"
)

var ch = make(chan int)

func consumer(ch chan int) {
	for {
		v := <-ch // 阻塞
		fmt.Printf("取出:%d\n", v)
	}
}

func main() {
	defer func() { // recover无法获取异常
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	ch <- 5 // 先写管道
	go consumer(ch) // 消费者协程
	time.Sleep(1 * time.Second)
}

// go run .\async_channel.go
// fatal error: all goroutines are asleep - deadlock!

// goroutine 1 [chan send]:
// main.main()
//         E:/go/async_channel.go:18 +0x40
// exit status 2
// 生产者协程,没有消费者阻塞住,不执行下去
package main

import (
	"fmt"
	"time"
)

var ch = make(chan int)

func consumer(ch chan int) {
	for {
		v := <-ch // 阻塞
		fmt.Printf("取出:%d\n", v)
	}
}

func main() {
	go func() {
		ch <- 5 // 阻塞住,不往下执行
		fmt.Println("发生成功")
	}()
	time.Sleep(1 * time.Second)
}

// go run sync_channel.go // 不打印,因为阻塞住了

异步channel

正常示例

package main

import "fmt"

var ch = make(chan int, 10)

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

func main() {
	send(ch)
}

// go run .\chan_example.go
send 0
send 1
send 2
send 3
send 4
send 5
send 6
send 7
send 8
send 9

main主协程,send管道满了:fatal error

package main

import "fmt"

var ch = make(chan int, 10)

func send(ch chan int) {
	for i := 0; i < 11; i++ {
		ch <- i
		fmt.Printf("send %d\n", i)
	}
}

func main() {
	send(ch)
}

// go run .\chan_example.go
send 0
send 1
send 2
send 3
send 4
send 5
send 6
send 7
send 8
send 9
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.send(0xc0000160b0)
        E:/GO_project/chan_example.go:16 +0x54
main.main()
        E:/GO_project/chan_example.go:22 +0x34
exit status 2

子协程管道满了会阻塞

package main

import "fmt"

var ch = make(chan int, 10)

func send(ch chan int) {
	for i := 0; i < 11; i++ {
		ch <- i
		fmt.Printf("send %d\n", i)
	}
}

func main() {
	go send(ch)
	time.Sleep(1 * time.Second)
}

// go run .\chan_example.go
send 0
send 1
send 2
send 3
send 4
send 5
send 6
send 7
send 8
send 9 // 观察到明显阻塞

main主协程,receive超出管道会fatal error

package main

import (
	"fmt"
	"time"
)

var ch = make(chan int, 10)

func receive(ch chan int) {
	for i := 0; i < 5; i++ {
		v := <-ch
		fmt.Printf("receive %d\n", v)
	}
}

func send(ch chan int) {
	for i := 0; i < 1; i++ {
		ch <- i
		fmt.Printf("send %d\n", i)
	}
}

func main() {
	send(ch)
	receive(ch)
	time.Sleep(1 * time.Second)
}

// go run .\chan_example.go
send 0
receive 0
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.receive(0xc00009c000)
        E:/GO_project/chan_example.go:12 +0x58
main.main()
        E:/GO_project/chan_example.go:26 +0x44
exit status 2

子协程管道取不出值,会阻塞

package main

import (
	"fmt"
	"time"
)

var ch = make(chan int, 10)

func receive(ch chan int) {
	for i := 0; i < 5; i++ {
		v := <-ch
		fmt.Printf("receive %d\n", v)
	}
}

func send(ch chan int) {
	for i := 0; i < 1; i++ {
		ch <- i
		fmt.Printf("send %d\n", i)
	}
}

func main() {
	send(ch)
	go receive(ch)
	time.Sleep(1 * time.Second)
}

// go run .\chan_example.go
send 0
receive 0

使用缓冲示例

package main

import (
	"fmt"
	"time"
)

var ch = make(chan int, 10)

func receive(ch chan int) {
	for i := 0; i < 5; i++ {
		v := <-ch
		fmt.Printf("receive %d\n", v)
	}
}

func send(ch chan int) {
	for i := 0; i < 15; i++ { // 超出了缓冲管道范围
		ch <- i
		fmt.Printf("send %d\n", i)
	}
}

func main() {
	go send(ch)
	go receive(ch)
	time.Sleep(1 * time.Second)
}

// go run .\chan_example.go
send 0
send 1
send 2
send 3
send 4
send 5
send 6
send 7
send 8
send 9
send 10
receive 0
receive 1
receive 2
receive 3
receive 4
send 11
send 12
send 13
send 14

管道先取值的话

func main() {
	go receive(ch)
	go send(ch)
	time.Sleep(1 * time.Second)
}

// go run .\chan_example.go
send 0
send 1
send 2
send 3
send 4
send 5
send 6
receive 0
receive 1
receive 2
receive 3
receive 4
send 7
send 8
send 9
send 10
send 11
send 12
send 13
send 14

子协程套子协程(孙协程)

package main

import (
	"fmt"
	"time"
)

func grandson() {
	fmt.Println("grnadson channel")
	time.Sleep(3 * time.Second)
	fmt.Println("grandson end")
}

func son() {
	fmt.Println("son channel")
	go grandson()
	time.Sleep(1 * time.Second)
	fmt.Println("son end")
}

func main(){
	fmt.Println("main channel")
	go son()
	time.Sleep(4 * time.Second)
	fmt.Println("main end")
}

// go run grandson_channel.go
main channel
son channel
grnadson channel
son end
grandson end
main end
package main

import (
	"fmt"
	"time"
)

func grandson() {
	fmt.Println("grnadson channel")
	time.Sleep(3 * time.Second)
	fmt.Println("grandson end")
}

func son() {
	fmt.Println("son channel")
	go grandson()
	time.Sleep(1 * time.Second)
	fmt.Println("son end")
}

func main(){
	fmt.Println("main channel")
	go son()
	time.Sleep(2 * time.Second)
	fmt.Println("main end")
}

// go run .\grandson_channel.go
main channel
son channel
grnadson channel
son end
main end
package main

import (
	"fmt"
	"time"
)

func grandson() {
	fmt.Println("grnadson channel")
	time.Sleep(1 * time.Second)
	fmt.Println("grandson end")
}

func son() {
	fmt.Println("son channel")
	go grandson()
	time.Sleep(1 * time.Second)
	fmt.Println("son end")
}

func main(){
	fmt.Println("main channel")
	go son()
	time.Sleep(1 * time.Second)
	fmt.Println("main end")
}

GMP模型

标签:fmt,Goroutine,Println,func,time,go,main
来源: https://www.cnblogs.com/Otiger/p/16221778.html