package main
import("fmt")
func fibonacci(n int, ch chan int){
a, b :=0,1for i :=0; i < n; i++{
ch <- a
a, b = b, a+b
}close(ch)}
func main(){
ch :=make(chan int,6)
go fibonacci(cap(ch), ch)for j := range ch {
fmt.Println(j)}}
用 sync 实现并发
互斥锁
package main
import("fmt""sync""time")
func main(){
var mutex sync.Mutex
wait := sync.WaitGroup{}
fmt.Println("Locked")
mutex.Lock()for i :=1; i <=5; i++{
wait.Add(1)
go func(i int){
fmt.Println("Not lock:", i)
mutex.Lock()
fmt.Println("Lock:", i)
time.Sleep(time.Second)
fmt.Println("Unlock:", i)
mutex.Unlock()
defer wait.Done()}(i)}
time.Sleep(time.Second)
fmt.Println("Unlocked")
mutex.Unlock()
wait.Wait()}
sync.Once 结构体
package main
import("fmt""sync")
func main(){
var once sync.Once
onceBody :=func(){
fmt.Println("test only once,这里只打印一次!")//打印}
done :=make(chan bool)for i :=0; i <6; i++{
go func(){
once.Do(onceBody)//确保只背执行一次
done <-true}()}for i :=0; i <6; i++{<-done
}}
同步等待组 zync.WaitGroup
package main
import("fmt""sync""time")
func main(){
var wg sync.WaitGroup
wg.Add(1)
go func(){
defer wg.Done()
fmt.Println("1 goroutine sleep ...")
time.Sleep(2)
fmt.Println("1 goroutine exit ...")}()
wg.Add(1)
go func(){
defer wg.Done()
fmt.Println("2 goroutine sleep ...")
time.Sleep(4)
fmt.Println("2 goroutine exit ...")}()
fmt.Println("Waiting for all goroutine ")
wg.Wait()
fmt.Println("All goroutines finished!")}
package main
import("fmt""sync""time")
func main(){
testFunc :=func(wg *sync.WaitGroup, id int){
defer wg.Done()
fmt.Printf("%v goroutine start ...\n", id)
time.Sleep(2)
fmt.Printf("%v goroutine exit ...\n", id)}
var wg sync.WaitGroup
const N =3
wg.Add(N)for i :=0; i < N; i++{
go testFunc(&wg, i)}
fmt.Println("Waiting for all goroutine")
wg.Wait()
fmt.Println("All goroutines finished!")}
竞态检测器
go run/build/test -race main.go
模拟非法竞态访问数据
package main
import"fmt"
func main(){
c :=make(chan bool)
m :=make(map[string]string)
go func(){
m["a"]="one"// 第一个冲突访问.
c <-true}()
m["b"]="two"// 第一个冲突访问<-c
for k, v := range m {
fmt.Println(k, v)}}
应用
自增整数生成器
package main
import"fmt"// 生成自增的整数
func IntegerGenerator() chan int{
var ch chan int=make(chan int)// 开启 goroutine
go func(){for i :=0;; i++{
ch <- i // 直到通道索要数据,才把i添加进信道}}()return ch
}
func main(){
generator :=IntegerGenerator()for i :=0; i <100; i++{//生成100个自增的整数
fmt.Println(<-generator)}}
并发消息发送器
package main
import"fmt"
func SendNotification(user string) chan string {//......此处省略查询数据库获取新消息。//声明一个通道来保存消息
notifications :=make(chan string,500)// 开启一个通道
go func(){//将消息放入通道
notifications <- fmt.Sprintf("Hi %s, welcome to our site!", user)}()return notifications
}
func main(){
barry :=SendNotification("barry")// 获取barry的消息
shirdon :=SendNotification("shirdon")// 获取shirdon的消息// 获取消息的返回
fmt.Println(<-barry)
fmt.Println(<-shirdon)}
多路复合计算器
package main
import("fmt""math/rand""time")// 这里可以是比较耗时的事情,比如计算
func doCompute(x int)int{
time.Sleep(time.Duration(rand.Intn(10))* time.Millisecond)//模拟计算return1+ x // 假如1 + x是一个很费时的计算}// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int{
ch :=make(chan int)
go func(){
ch <-doCompute(x)}()return ch
}
func Recombination(chs ...chan int) chan int{
ch :=make(chan int)for _, c := range chs {// 注意此处明确传值
go func(c chan int){ ch <-<-c }(c)// 复合}return ch
}
func main(){//返回复合结果
result :=Recombination(branch(10),branch(20),branch(30))for i :=0; i <3; i++{
fmt.Println(<-result)}}
用 select 关键字创建多通道监听器
package main
import("fmt")
func foo(i int) chan int{
ch :=make(chan int)
go func(){ ch <- i }()return ch
}
func main(){
ch1, ch2, ch3 :=foo(3),foo(6),foo(9)
ch :=make(chan int)// 开一个goroutine监视各个通道数据输出并收集数据到通道ch
go func(){for{// 监视ch1, ch2, ch3的流出,并全部流入通道ch
select {case v1 :=<-ch1:
ch <- v1
case v2 :=<-ch2:
ch <- v2
case v3 :=<-ch3:
ch <- v3
}}}()// 阻塞主线,取出通道ch的数据for i :=0; i <3; i++{
fmt.Println(<-ch)}}
多路复合计算器
package main
import("fmt""math/rand""time")//这里可以是比较耗时的事情,比如计算
func doCompute(x int)int{
time.Sleep(time.Duration(rand.Intn(10))* time.Millisecond)//模拟计算return1+ x // 假如1 + x是一个很费时的计算}// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int{
ch :=make(chan int)
go func(){
ch <-doCompute(x)}()return ch
}
func Recombination(branches ... chan int) chan int{
ch :=make(chan int)//select会尝试着依次取出各个通道的数据
go func(){for i :=0; i <len(branches); i++{
select {case v1 :=<-branches[i]:
ch <- v1
}}}()return ch
}
func main(){//返回复合结果
result :=Recombination(branch(10),branch(20),branch(30))for i :=0; i <3; i++{
fmt.Println(<-result)}}
package main
import("fmt")
func main(){
ch, quit :=make(chan int),make(chan int)
go func(){
ch <-8// 添加数据
quit <-1// 发送完成信号}()for isQuit :=false;!isQuit;{// 监视通道ch的数据流出
select {case v :=<-ch:
fmt.Printf("received %d from ch", v)case<-quit:
isQuit =true// quit通道有输出,关闭for循环}}}
用筛法求素数
package main
import"fmt"//生成自增的整数
func IntegerGenerator() chan int{
var ch chan int=make(chan int)
go func(){// 开出一个goroutinefor i :=2;; i++{
ch <- i // 直到通道索要数据,才把i添加进通道}}()return ch
}
func Filter(in chan int, number int) chan int{// 输入一个整数队列,筛出是number倍数的, 不是number的倍数的放入输出队列// in: 输入队列
out :=make(chan int)
go func(){for{
i :=<-in // 从输入中取一个if i%number !=0{
out <- i // 放入输出通道}}}()return out
}
func main(){const max =100// 找出100以内的所有素数
numbers :=IntegerGenerator()// 初始化一个整数生成器
number :=<-numbers // 从生成器中抓一个整数(2), 作为初始化整数for number <= max {// number作为筛子,当筛子超过max的时候结束筛选
fmt.Println(number)// 打印素数, 筛子即一个素数
numbers =Filter(numbers, number)//筛掉number的倍数
number =<-numbers // 更新筛子}}
创建随机数生成器
package main
import"fmt"
func randGenerator() chan int{
ch :=make(chan int)
go func(){for{//select会尝试执行各个case, 如果都可以执行,那么随机选一个执行
select {case ch <-0:case ch <-1:}}}()return ch
}
func main(){//初始化一个随机生成器
generator :=randGenerator()//测试,打印10个随机数for i :=0; i <10; i++{
fmt.Println(<-generator)}}