package main
import("fmt""strconv""sync""time")var(
myMap =make(map[int]uint64,10)
lock sync.Mutex
)functest(){for i :=0; i <7; i++{
fmt.Println("hello,world"+ strconv.Itoa(i))
time.Sleep(time.Second)}}funcmain(){// go test()// for i := 0; i < 10; i++ {// fmt.Println("hello,world" + strconv.Itoa(i))// time.Sleep(time.Second)// }for i :=1; i <=200; i++{gocal(i)}
time.Sleep(time.Second *5)
lock.Lock()for i, v :=range myMap {
fmt.Printf("map[%d]%d\n", i, v)}
lock.Unlock()}funccal(n int){var res uint64=1for i :=1; i <= n; i++{
res *=uint64(i)}
lock.Lock()
myMap[n]= res
lock.Unlock()}
上面的代码为低级的用法,使用到了锁,后面用管道来进行解决。
下面是管道的一些用法,要注意接口类型的管道
package main
import("fmt")funcmain(){var intChan chanintvar mapChan chanmap[string]int// var sliceChan chan []map[int]int
intChan =make(chanint,3)
fmt.Printf("intchan %T %p\n", intChan,&intChan)
intChan <-10
num :=211
intChan <- num
fmt.Printf("intchan len = %v cap = %v ",len(intChan),cap(intChan))
num2 :=<-intChan
intChan <-<-intChan
fmt.Printf("intchan len = %v cap = %v \n",len(intChan),cap(intChan))
fmt.Println(num2)
mapChan =make(chanmap[string]int,30)
m1 :=make(map[string]int,10)
m1["北京"]=10
m1["tianjin"]=10
m2 :=make(map[string]int,10)
m2["北京"]=10
m2["tianjin"]=10
mapChan <- m1
mapChan <- m2
fmt.Printf("intchan len = %v cap = %v \n",len(mapChan),cap(mapChan))//下面是interface{}类型的管道注意var interChan chaninterface{}
interChan =make(chaninterface{},10)
s1 :=make([]int,10)
s1 =[]int{10,20}type Cat struct{
Name string
Age int}type Dog struct{
Name string}
interChan <-"hello"
interChan <-111
interChan <-111.111
interChan <- s1
cat := Cat{
Name:"qiuqiu",
Age:2,}
interChan <- cat
str :=<-interChan
<-interChan
<-interChan
slice :=<-interChan
newCat :=<-interChan
fmt.Printf("%T\n%v\n", str, str)
fmt.Printf("%T\n%v\n", slice, slice)
fmt.Printf("%T\n%v\n", newCat, newCat)_, ok := newCat.(Dog)//类型断言,故意举个错误的例子,联系一下类型断言是返回两个值,一个值原来的值,一个是布尔值/*正常是
a,ok := newCat(Cat)
if ok {
fmt.Println(a.Name)
}
*/if!ok {
fmt.Println("a.Name")}
fmt.Printf("interchan len = %v cap = %v \n",len(interChan),cap(interChan))//channel 关闭时不可以写,但是可以读//遍历管道,用 for-range
intChan2 :=make(chanint,100)for i :=1; i <=100; i++{
intChan2 <- i *2}//遍历时,如果channel没有关闭,则会出现deadlock的错误:fatal error: all goroutines are asleep - deadlock!//如果已经关闭管道,则会正常遍历数据,遍历完后,退出遍历close(intChan2)//管道只返回一个值,没有所谓的下标for v :=range intChan2 {
fmt.Printf("值为%d\n", v)}/*
上面这个情况是明确知道管道什么时候关闭,用for range来遍历,
当不知道什么时候关闭,仍想遍历时,用select方法
label:
for{
select{
//注意:这里,如果intChan一直没有关闭,不会一直阻塞而deadlock
//会自动匹配到下一个case
case v:=<-intChan:
fmt.Printf("从intChan取出值为%d\n", v)
case v:=<-stringChan:
fmt.Printf("从stringChan取出值为%s\n", v)
default:
fmt.Println("都取不到值了,程序员可以加入自己的逻辑")
//return //用return直接退出整个程序或者用label,不推荐
break label
}
}
*/}
管道解决问题时,注意要再开一个管道用来存储状态,如下
package main
import("fmt""time")/*
解决一个实际的问题,
同时向一个管道进行写入数据和输出数据
一个管道正常存入存储数据
再开一个退出管道用来记录上面这个管道的状态,如果读完数据,在这个管道写入true,并关闭退出管道
然后在主线程一直for循环读取退出管道,读到true退出
*/funcWriteData(intchan chanint){for i :=1; i <=100; i++{
intchan <- i *2
fmt.Println("写入数据", i*2)}close(intchan)}funcReadData(intchan chanint, exitchan chanbool){for{
v, ok :=<-intchan
if!ok {break}
fmt.Println(v)
time.Sleep(time.Second)}
exitchan <-trueclose(exitchan)}funcmain(){
intchan :=make(chanint,10)
exitchan :=make(chanbool,1)goWriteData(intchan)goReadData(intchan, exitchan)for{_, ok :=<-exitchan
if!ok {break}}}
管道和协程解决一个问题,求素数,用到了上面的想法
package main
import("fmt""time")/*
求素数
*///放数据funcputNum(intChan chanint){//这里要是想变成只写的,可以这样传参intChan chan<- int,这样可以将本来是双向的在这个函数里面变成只写,避免误操作//只读也一样,变成 intChan <-chan intfor i :=1; i <8000; i++{
intChan <- i
}close(intChan)}// 取数据funcprimeNum(intChan, primeChan chanint, exitChan chanbool){// var num intvar flag boolfor{
time.Sleep(time.Millisecond)
num, ok :=<-intChan
if!ok {break}
flag =truefor i :=2; i < num; i++{if num%i ==0{
flag =falsebreak}}if flag {
primeChan <- num
}}
fmt.Println("有一个协程退出")//这里不能关闭primeChan,可能其他还在处理,向一个退出管道写入true即可
exitChan <-true}funcmain(){
intChan :=make(chanint,8000)
primeChan :=make(chanint,3000)
exitChan :=make(chanbool,4)//放数goputNum(intChan)//判断是否为素数for i :=1; i <=cap(exitChan); i++{goprimeNum(intChan, primeChan, exitChan)}//当写入四个true时,才关闭管道gofunc(){for{iflen(exitChan)==4{close(primeChan)break}}}()//遍历primeChan,取出数字for{
res, ok :=<-primeChan
if!ok {break}
fmt.Println(res)}
fmt.Println("main exit")}
对于不想因为一个协程出错而导致其他的不能运行,可以在协程适当位置添加recover来捕获panic
package main
import("fmt""time")funcsayHello(){for i :=1; i <10; i++{
fmt.Printf("sayHello,%d\n", i)}}functest(){var myMap map[string]int//故意没有make一下,引出错误处理机制,之前学过defer+recoverdeferfunc(){//捕获panicif err :=recover(); err !=nil{
fmt.Println("发生错误,", err)}}()
myMap["1"]=1}funcmain(){gosayHello()gotest()for i :=1; i <10; i++{
fmt.Printf("main , %d\n", i)
time.Sleep(time.Second)}}