1.goroutine
package main
import(
"fmt"
"math"
"sync"
)
func sum(id int) {
var x int64
for i := 0; i < math.MaxUint32; i++ {
x+=int64(i)
}
fmt.Println(id,x)
}
func main() {
wg:=new(sync.WaitGroup)
wg.Add(2)
for i := 0; i < 2; i++ {
go func(id int) {
defer wg.Done()
sum(id)
}(i)
}
wg.Wait()
}
输出:
0 9223372030412324865
1 9223372030412324865
2.runtime.Goexit()
package main
import(
"fmt"
//"math"
"sync"
"runtime"
)
func main() {
wg:=new(sync.WaitGroup)
wg.Add(1)
go func() {
defer wg.Done()
defer fmt.Println("A.defer")
func () {
defer fmt.Println("B.defer")
runtime.Goexit() //终止当前goroutine
fmt.Println("B") //不会执行
}()
fmt.Println("A") //不会执行
}()
wg.Wait()
}
输出:
B.defer
A.defer
3.runtime.Gosched()
package main
import(
"fmt"
//"math"
"sync"
"runtime"
)
func main() {
wg:=new(sync.WaitGroup)
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 6; i++ {
fmt.Println(i)
if i==3 {runtime.Gosched()}
}
}()
go func() {
defer wg.Done()
fmt.Println("Hello,World!")
}()
wg.Wait()
}
输出:
0
1
2
3
Hello,World!
4
5
或者输出:
Hello,World!
0
1
2
3
4
5
4.channel
package main
import(
"fmt"
//"math"
//"sync"
//"runtime"
)
func main() {
data:=make(chan int) //数据交换队列
exit:=make(chan bool) //退出通知
go func () {
for d:=range data{ //从队列迭代接受数据,直到close
fmt.Println(d)
}
fmt.Println("recv over!")
exit<-true //发送退出通知
}()
data <- 1 //发送数据
data <- 2
data <- 3
data <- 4
data <- 5
close(data) //关闭队列
fmt.Println("send over.")
<- exit //等待退出通知
}
输出:
1
2
3
4
5
recv over!
send over.
除用 range 外,还可用 ok-idiom 模式判断 channel 是否关闭。
for {
if d, ok := <-data; ok {
fmt.Println(d)
} else {
break
}
}
内置函数 len 返回未被读取的缓冲元素数量, cap 返回缓冲区大小。
5.单向channel
可以将
channel
隐式转换为单向队列,只收或只发。
c := make(chan int, 3)
var send chan<- int = c // send-only
var recv <-chan int = c // receive-only
send <- 1
// <-send // Error: receive from send-only type chan<- int
<-recv
// recv <- 2 // Error: send to receive-only type <-chan int
选择channel
package main
import(
"fmt"
"os"
//"math"
//"sync"
//"runtime"
)
func main() {
a:=make(chan int,3)
b:=make(chan int)
go func() {
v,ok,s:=0,false,""
for{
select{ //随机选择可用的channel,接受数据
case v,ok= <-a : s="a"
case v,ok= <-b : s="b"
}
if ok{
fmt.Println(s,v)
}else{
os.Exit(0)
}
}
}()
for i := 0; i<10; i++ {
select{ //随机选择可用的channel,发送数据
case a<-i:
case b<-i:
}
}
close(a)
select{} //没有可用channel,阻塞main goroutine
}
输出:
a 0
b 4
a 1
b 6
a 2
a 3
b 9
a 5
a 7
a 8
6.模式
1.用简单工厂模式打包并发任务和channel
package main
import(
"fmt"
//"os"
//"rand"
"time"
"math/rand"
//"sync"
//"runtime"
)
//用简单工厂模式打包并发任务和channel
func NewTest() chan int {
c:=make(chan int)
rand.Seed(time.Now().UnixNano())//使用rand.Int 获取随机数,不加随机种子,每次遍历获取都是重复的一些数据
go func() {
time.Sleep(time.Second)
c<-rand.Int()
}()
return c
}
func main() {
t:=NewTest()
fmt.Println(<-t)
}
2.用channel 实现信号量 (semaphore)。
package main
import(
"fmt"
//"os"
//"rand"
//"time"
//"math/rand"
"sync"
//"runtime"
)
func main() {
wg:=sync.WaitGroup{}
wg.Add(3)
sem:=make(chan int,1)
for i := 0; i < 3; i++ {
go func(id int) {
defer wg.Done()
sem <- 1 //向sem发送数据,阻塞或者成功
for x := 0; x < 5; x++ {
fmt.Println(id,x)
}
<- sem //接受数据,使得其他阻塞goroutine可以发送数据。
}(i)
}
wg.Wait()
}
输出:
0 0
0 1
0 2
0 3
0 4
2 0
2 1
2 2
2 3
2 4
1 0
1 1
1 2
1 3
1 4
0 1
0 2
0 3
0 4
2 0
2 1
2 2
2 3
2 4
1 0
1 1
1 2
1 3
1 4
3.用closed channel 发送退出通知
package main
import(
"fmt"
//"os"
//"rand"
"time"
//"math/rand"
"sync"
//"runtime"
)
func main() {
var wg sync.WaitGroup
quit:=make(chan bool)
for i := 0; i < 2; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
task:=func() {
fmt.Println(id,time.Now().Nanosecond())
time.Sleep(time.Second)
}
for{
select{
case <-quit: //closed channel 不会阻塞,因此可用作退出通知
return
default: //执行正常的任务
task()
}
}
}(i)
}
time.Sleep(time.Second*5) //让测试goroutine运行一会儿
close(quit) //发出退出通知
wg.Wait()
}
输出:
0 268850000
1 268850000
1 268850000
0 268850000
0 268850000
1 268850000
1 268850000
0 268850000
0 268850000
1 268850000
0 268850000
退出
4.用select实现超时(timeout),
5.channel 是第一类对象,可传参 (内部实现为指针) 或者作为结构成员。