0 goroutine是否并发的问题
GoLang通过go关键字实现并发操作(真的并发吗?),一个最简单的并发模型:
- packagemain
-
- import(
- "fmt"
- "math/rand"
- "time"
- )
-
- funcroutine(namestring,delaytime.Duration){
- t0:=time.Now()
- fmt.Println(name,"startat",t0)
-
-
- time.Sleep(delay)
-
- t1:=time.Now()
- fmt.Println(name,54)">"endat",t1)
-
-
- fmt.Println(name,54)">"lasted",t1.Sub(t0))
-
- }
-
- funcmain(){
-
-
- rand.Seed(time.Now().Unix())
-
-
- fmt.Println(time.Duration(5)*time.Second)
-
- varnamestring
- fori:=0;i<3;i++{
- name=fmt.Sprintf("go_%02d",i)
-
-
-
- goroutine(name,time.Duration(rand.Intn(5))*time.Second)
- }
-
-
- varinputstring
- fmt.Scanln(&input)
- fmt.Println("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)
time.Sleep(delay)
t1:=time.Now()
fmt.Println(name,t1)
fmt.Println(name,t1.Sub(t0))
}
funcdie_routine(){
for{
}
}
funcmain(){
runtime.GOMAXPROCS(4)
fmt.Println("setruntime.GOMAXPROCS")
fmt.Println(time.Duration(5)*time.Second)
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())
fori:=0;i<5;i++{
gosell_tickets(i)
}
varinputstring
fmt.Scanln(&input)
fmt.Println(total_tickets,54)">"done")
}
上述例子没有考虑并发安全问题,因此需要加一把锁以保证每个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(){
2 并发情况下的原子操作问题
go语言也支持原子操作。关于原子操作可以参考耗子叔叔这篇文章《
无锁队列的实现
》,里面说到了一些CAS – CompareAndSwap的操作。下面的程序有10个goroutine,每个会对cnt变量累加20次,所以,最后的cnt应该是200。如果没有atomic的原子操作,那么cnt将有可能得到一个小于200的数。下面使用了atomic操作,所以是安全的。
"sync/atomic"
"time"
)
funcmain(){
varcntuint32=0
fori:=0;i<10;i++{
gofunc(){
fori:=0;i<20;i++{
time.Sleep(time.Millisecond)
atomic.AddUint32(&cnt,1)
}
}()
}
time.Sleep(time.Second*2)
cntFinal:=atomic.LoadUint32(&cnt)
fmt.Println("cnt:",cntFinal)
}
转帖自http://blog.csdn.net/delphiwcdj/article/details/17630863
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|