0 goroutine是否并发的问题
GoLang通过go关键字实现并发操作(真的并发吗?),一个最简单的并发模型:
- packagemain
- import(
- "fmt"
- "math/rand"
- "time"
- )
- funcroutine(namestring,delaytime.Duration){
- t0:=time.Now()
- fmt.Println(name,"startat",t0)
- //停留xxx秒
- time.Sleep(delay)
- t1:=time.Now()
- fmt.Println(name,54)">"endat",t1)
- //计算时间差
- fmt.Println(name,54)">"lasted",t1.Sub(t0))
- }
- funcmain(){
- //生成随机种子,类似C语言中的srand((unsigned)time(0))生成随机种子
- rand.Seed(time.Now().Unix())
- //ToconvertanintegernumberofunitstoaDuration,multiply
- fmt.Println(time.Duration(5)*time.Second)
- varnamestring
- fori:=0;i<3;i++{
- name=fmt.Sprintf("go_%02d",i)//生成ID
- //生成随机等待时间,从0-4秒
- //ntnreturns,asanint,anon-negativepseudo-randomnumberin[0,n)fromthedefaultSource.Itpanicsifn<=0.
- goroutine(name,time.Duration(rand.Intn(5))*time.Second)
- }
- //让主进程停住,不然主进程退了,goroutine也就退了
- varinputstring
- fmt.Scanln(&input)
- fmt.Println("done")
- }
- /*
- output:
- mba:testgerryyang$./rand_t
- 5s
- go_00startat2013-12-2813:25:04.460768468+0800HKT
- go_01startat2013-12-2813:25:04.460844141+0800HKT
- go_02startat2013-12-2813:25:04.460861337+0800HKT
- go_02endat2013-12-2813:25:04.460984329+0800HKT
- go_02lasted122.992us
- go_01endat2013-12-2813:25:05.462003787+0800HKT
- go_01lasted1.001159646s
- go_00endat2013-12-2813:25:07.461884807+0800HKT
- go_00lasted3.001116339s
- done
- */
关于goroutine是否真正并发的问题,耗子叔叔这里是这样解释的:
引用:
“关于goroutine,我试了一下,无论是Windows还是Linux,基本上来说是用操作系统的线程来实现的。不过,goroutine有个特性,也就是说,如果一个goroutine没有被阻塞,那么别的goroutine就不会得到执行。这并不是真正的并发,如果你要真正的并发,你需要在你的main函数的第一行加上下面的这段代码:
- importruntime
- runtime.GOMAXPROCS(n)
”
本人使用go1.2版本在Linux64,2.6.32内核环境下测试,在上述代码中再添加一个死循环的routine,可以验证上述的逻辑。在没有设置GOMAXPROCS参数时,多个goroutine会出现阻塞的情况;设置GOMAXPROCS参数时,下面的几个routine可以正常执行不会被阻塞。
"time"
"runtime"
)
funcroutine(namestring,delaytime.Duration){
t0:=time.Now()
fmt.Println(name,t0,",sleep:",delay)
//停留xxx秒
time.Sleep(delay)
t1:=time.Now()
fmt.Println(name,t1)
//计算时间差
fmt.Println(name,t1.Sub(t0))
}
funcdie_routine(){
for{
//dieloop
}
}
funcmain(){
//实现真正的并发
runtime.GOMAXPROCS(4)
fmt.Println("setruntime.GOMAXPROCS")
fmt.Println(time.Duration(5)*time.Second)
//dieroutine
godie_routine()
varnamestring
fori:=0;i<3;i++{
name=fmt.Sprintf(//生成ID
goroutine(name,time.Duration(rand.Intn(5))*time.Second)
}
varinputstring
fmt.Scanln(&input)
fmt.Println("done")
}
1 goroutine非并发安全性问题
这是一个经常出现在教科书里卖票的例子,启了5个goroutine来卖票,卖票的函数sell_tickets很简单,就是随机的sleep一下,然后对全局变量total_tickets作减一操作。
"time"
"math/rand"
"runtime"
)
vartotal_ticketsint32=10
funcsell_tickets(iint){
for{
//如果有票就卖
iftotal_tickets>0{
time.Sleep(time.Duration(rand.Intn(5))*time.Millisecond)
//卖一张票
total_tickets--
fmt.Println("id:",i,54)">"ticket:",total_tickets)
}else{
break
}
}
}
funcmain(){
//设置真正意义上的并发
runtime.GOMAXPROCS(4)
//生成随机种子
rand.Seed(time.Now().Unix())
//并发5个goroutine来卖票
fori:=0;i<5;i++{
gosell_tickets(i)
}
//等待线程执行完
varinputstring
fmt.Scanln(&input)
//退出时打印还有多少票
fmt.Println(total_tickets,54)">"done")
}
id:1ticket:8
id:0ticket:8
id:0ticket:7
id:2ticket:5
id:4ticket:6
id:4ticket:3
id:3ticket:3
id:1ticket:1
id:0ticket:2
id:3ticket:-1
id:2ticket:-1
id:1ticket:-2
id:4ticket:-3
-3done
*/
上述例子没有考虑并发安全问题,因此需要加一把锁以保证每个routine在售票的时候数据同步。
"runtime"
"sync"
)
vartotal_ticketsint32=10
varmutex=&sync.Mutex{}
funcsell_tickets(iint){
fortotal_tickets>0{
mutex.Lock()
//如果有票就卖
iftotal_tickets>0{
time.Sleep(time.Duration(rand.Intn(5))*time.Millisecond)
//卖一张票
total_tickets--
fmt.Println( }
mutex.Unlock()
}
}
funcmain(){
id:0ticket:9
id:0ticket:6
id:0ticket:5
id:0ticket:4
id:0ticket:3
id:0ticket:2
id:0ticket:1
id:0ticket:0
0done
*/
2 并发情况下的原子操作问题
go语言也支持原子操作。关于原子操作可以参考耗子叔叔这篇文章《 无锁队列的实现 》,里面说到了一些CAS – CompareAndSwap的操作。下面的程序有10个goroutine,每个会对cnt变量累加20次,所以,最后的cnt应该是200。如果没有atomic的原子操作,那么cnt将有可能得到一个小于200的数。下面使用了atomic操作,所以是安全的。
"sync/atomic"
"time"
)
funcmain(){
varcntuint32=0
//启动10个goroutine
fori:=0;i<10;i++{
gofunc(){
//每个goroutine都做20次自增运算
fori:=0;i<20;i++{
time.Sleep(time.Millisecond)
atomic.AddUint32(&cnt,1)
}
}()
}
//等待2s,等goroutine完成
time.Sleep(time.Second*2)
//取最终结果
cntFinal:=atomic.LoadUint32(&cnt)
fmt.Println("cnt:",cntFinal)
}
cnt:200
*/
原文链接:https://www.f2er.com/go/191128.html
转帖自http://blog.csdn.net/delphiwcdj/article/details/17630863