在Go中,使用go 跟上一个函数就创建一个goroutine,每个goroutine可以任务是一个轻量级线程,占用更少的堆栈内存,并且可以自己在运行时动态增加/回收;
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
// 函数退出时会执行
defer fmt.Println("---main goroutine over---")
wg.Add(1)
go func() {
fmt.Println("goroutine hi")
wg.Done()
}()
fmt.Println("--wait sub goroutine over--")
// 阻塞等待goroutine结束
wg.Wait()
fmt.Println("---sub goroutine over---")
}
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func printMsg() {
fmt.Println("goroutine hi")
wg.Done()
}
func main() {
// 函数退出时会执行
defer fmt.Println("---main goroutine over---")
wg.Add(1)
go printMsg()
fmt.Println("--wait sub goroutine over--")
wg.Wait()
fmt.Println("---sub goroutine over---")
}
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func printMsg() {
fmt.Println("goroutine hi")
wg.Done()
// 循环打印
for {
fmt.Println("yeyeye")
}
}
func main() {
// 函数退出时会执行
defer fmt.Println("---main goroutine over---")
wg.Add(1)
go printMsg()
fmt.Println("--wait sub goroutine over--")
wg.Wait()
fmt.Println("---sub goroutine over---")
}
package main
import (
"fmt"
"time"
)
func main() {
// 函数退出时会执行
defer fmt.Println("---main goroutine over---")
quit := make(chan struct{})
go func() {
// 监听机制
select {
监听quit有数据
case <-quit:
fmt.Println("sub goroutine over")
return
default:
for {
time.Sleep(1 * time.Second)
fmt.Println("hihi")
}
}
}()
// do something
time.Sleep(5 * time.Second)
fmt.Println("--stop sub goroutine over--")
// 本质quit中写入零值,子goroutine监听到就会退出
close(quit)
time.Sleep(10 * time.Second)
}
package main
func main() {
// 创建一个无缓冲通道,两种方式
ch1 := make(chan int)
/*var ch1 chan int = make(chan int)
// 创建有缓冲通道
ch2 := make(chan int, 10) // 缓冲数为10
var ch2 chan int = make(chan int, 10)*/
// 通道写入数据
ch1 <- 1 // 写入
ch1 <- 2 // 此时因为ch1内的数据没有被消费,会阻塞*/
<-ch1 // 读取元素
num := <-ch1 // 读取元素到变量num,此时会因为没有元素被阻塞
}
package main
import "fmt"
// ch只读取,wg只写入
func printer(ch <-chan int, wg chan<- int) {
// 打印通道元素,没有则阻塞
for i := range ch {
fmt.Println(i)
}
// 写入元素
wg <- 1
// 关闭通道,只可以读通道元素不能再写
close(wg)
}
func main() {
// 创建缓冲通道
ch := make(chan int, 10)
// 创建同步用的无缓冲通道
wg := make(chan int)
go printer(ch, wg)
// 写入元素,激活激活的goroutine
for i := 1; i < 100; i++ {
ch <- i
}
// 关闭协程,不能写,只能读
close(ch)
fmt.Println("wait sub goroutine over")
// 当printer goroutine没有运行完,会一直阻塞,等待wg中有元素
<-wg
fmt.Println("main goroutine over")
}
// gen函数,nums表示多个int类型数据,多参数 返回一个只读取的通道, 不会阻塞
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
// 写入所有数据,然后关闭通道,写入一个之后等待消费者消费后,才可以再次写入
for _, n := range nums {
out <- n
}
// close 后不能写入,其他goroutine读取out的数据完之后就会退出不在阻塞
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
//异步的从in获取数据,开始是阻塞的,遍历写入out,当gen调用close(out)后就会不在阻塞等待in的数据
for n := range in {
out <- n * n
}
// 通知main goroutine的for 通道数据写入完,读取完就可以了,不用阻塞了
close(out)
}()
return out
}
测试:
package main
import (
"fmt"
)
// gen函数,nums表示多个int类型数据,多参数 返回一个只读取的通道, 不会阻塞
func gen(nums ...int) <-chan int {
out := make(chan int)
go func() {
// 写入所有数据,然后关闭通道,写入一个之后等待消费者消费后,才可以再次写入
for _, n := range nums {
out <- n
}
// close 后不能写入,其他goroutine读取out的数据完之后就会退出不在阻塞
close(out)
}()
return out
}
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
//异步的从in获取数据,开始是阻塞的,遍历写入out,当gen调用close(out)后就会不在阻塞等待in的数据
for n := range in {
out <- n * n
}
// 通知main goroutine的for 通道数据写入完,读取完就可以了,不用阻塞了
close(out)
}()
return out
}
func main() {
c := gen(2, 3)
out := sq(c)
// 类似于JAVA CompleteFuture.thenApply ..等
for i := range out{
fmt.Println(i)
}
}
同样的sq函数输入,输出类似,可以多次调用该节点
func main() {
c := gen(2, 3)
out := sq(c)
out = sq(out)
// 类似于JAVA CompleteFuture.thenApply ..等
for i := range out{
fmt.Println(i)
}
}
func merge(cs ...<-chan int) <-chan int {
var wg sync.WaitGroup
// 输出通道
out := make(chan int)
// 函数:将输入通道元素写入元素的输入通道
outPut := func(c <-chan int) {
for n := range c {
out <- n
}
wg.Done()
}
// cs 数量的信号量
wg.Add(len(cs))
for _, c := range cs {
go outPut(c)
}
// 等待输入通道所有数据全部写入输出通道
go func() {
wg.Wait()
close(out)
}()
return out
}
测试:
func main() {
c := gen(2, 3)
// 由于两个sq是并发的,可能是4先写入meger通道也可能是9
out := sq(c)
out1 := sq(c)
// 4,9 / 9,4
for i := range merge(out, out1) {
fmt.Println(i)
}
}