作者: 一字马胡
转载标志 【2017-11-25】
更新日志
日期 | 更新内容 | 备注 |
---|---|---|
2017-11-25 | 新建文章 | go语言入门学习笔记(四) |
golang入门学习笔记系列
golang入门学习笔记(一)
golang入门学习笔记(二)
golang入门学习笔记(三)
Atomic Counters
所谓Atomic,也就是不可中断的操作,下面是go语言中使用Atomic的例子:
// Atomic test
// using nGoroutines goroutines to atomic the counter
// you should sleep some time to test atomic.
func testAtomicCounter(nGoroutines int, counter *int64) {
if nGoroutines == 0 {
nGoroutines = 100 //default goroutines
}
for i := 0; i < nGoroutines; i ++ {
go func() {
for {
//atomic add
atomic.AddInt64(counter, 1)
//no cpu 100%
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
}
} ()
}
}
var counter int64 = 0
var nGoroutines = 50
testAtomicCounter(nGoroutines, &counter)
//sleep 2 secs to wait the atomic test func
time.Sleep(time.Second * time.Duration(2))
counterCopy := atomic.LoadInt64(&counter)
log.Printf("The Atomic Result:%d", counterCopy)
上面的例子使用多个goroutine来模拟并发竞争,counter是我们维护的计数器。
Mutexes
Mutexes类似于锁,可以使用Mutexes来安全的访问多个goroutine共享的数据,下面是一个使用Mutexes的例子:
//test the Mutexes
//using nGoroutines goroutines to mock ops.
//the share will be ref many goroutines
//the mutext is the "lock"
func testMutexes(nGoroutines int, share *int32, mutex sync.Mutex) {
if nGoroutines == 0 {
nGoroutines = 100
}
for i := 0; i < nGoroutines; i ++ {
go func() {
rdm := rand.Int31n(10)
//lock the share
mutex.Lock()
*share += rdm
//unlock the share
mutex.Unlock()
//no cpu 100%
time.Sleep(time.Second * time.Duration(3))
} ()
}
}
var nGoroutines = 50
var texes = &sync.Mutex{}
var share int32 = 0
testMutexes(nGoroutines, &share, *mutexes)
time.Sleep(time.Second * time.Duration(5))
shareCopy := atomic.LoadInt32(&share)
log.Printf("share:%d\n", shareCopy)
上面的代码使用Mutexes来显示的将多个goroutine共享的share锁住再进行操作。
Stateful Goroutines
除了上面介绍的使用Mutexes来进行多个goroutine同步之外,另一个选择是使用 goroutine 和 channel 内置的同步功能来达到相同的结果,下面是一个例子:
//just test the goroutine "sync" at 2017-11-25 11:13
//
func test201711251113() {
//read op
type readOp struct {
key int
value chan int
}
//write op
type writeOp struct {
key int
value int
res chan bool
}
reads := make(chan *readOp)
writes := make(chan *writeOp)
go func() {
//the share map
var share = make(map[int]int)
for {
select {
case read := <- reads:
read.value <- share[read.key] // read map and send it
case write := <- writes:
key := write.key
value := write.value
share[key] = value
write.res <- true
}
}
} ()
nWrites := 100
nReads := 50
for i := 0; i < nReads; i ++ {
go func() {
for {
read := &readOp{
key:rand.Intn(10),
value:make(chan int),
}
reads <- read
v := <-read.value
log.Printf("read value:%d for key:%d\n", v, read.key)
//no cpu 100%
time.Sleep(time.Millisecond * time.Duration(2000))
}
} ()
}
for i := 0; i < nWrites; i ++ {
go func() {
for {
write := &writeOp{
key:rand.Intn(10),
value:rand.Intn(10),
res:make(chan bool),
}
writes <- write
<- write.res
log.Printf("write value:%d for key:%d\n", write.value, write.key)
//no cpu 100%
time.Sleep(time.Millisecond * time.Duration(2000))
}
} ()
}
//wait some times
time.Sleep(time.Second * time.Duration(3))
}
golang博大精深,还得慢慢学习体会其中的深意啊!
Sort for golang
go对slice支持内置和自定义两种类型的排序,需要注意的是排序是在原来的slice上进行的,而不会生成一个新的slice,下面是一个go语言的sort的使用示例:
//struct of key-value pair
//
type key_value struct {
key int
value int
}
//key-value array
type keyValues []key_value
func (kvs keyValues) Len() int{
return len(kvs)
}
func (kvs keyValues) Swap(i, j int) {
kvs[i], kvs[j] = kvs[j], kvs[i]
}
func (kvs keyValues) Less(i, j int) bool {
kvI := kvs[i]
kvJ := kvs[j]
if (kvI.key == kvJ.key) {
return kvI.value <= kvJ.value
} else {
return kvI.key <= kvJ.key
}
}
//just test the sort of golang
// 2017-11-25 11:33
func testSort() {
orgString := []string {"a", "c", "b", "e", "d"}
sort.Strings(orgString)
fmt.Print(orgString, "\n")
ints := []int {1, 2, 5, 3, 10, 4}
if sort.IntsAreSorted(ints) {
fmt.Print("the ints are sorted!\n")
}
sort.Ints(ints)
fmt.Print(ints, "\n")
kvs := []key_value {
key_value{key:1,value:3},
key_value{key:1,value:2},
key_value{key:2,value:3},
}
sort.Sort(keyValues(kvs))
fmt.Print(kvs, "\n")
}
上面的代码首先根据内置的排序进行排序实验,然后自定义了一种类型,并且对该类型进行自定义排序,排序的规则可以看Less方法的具体实现,如果我们想要实现自定义的排序,就需要实现Sort接口的三个方法,实现之后就可以使用sort方法来进行自定义排序了。
defer for golang
defer类似于java语言中的finally语句块,用于在函数返回之前做一些处理,常用于在函数返回之前做一些资源回收的操作,比如打开的文件资源,需要注意的一点是,当有多个defer的时候,defer的执行是FILO的,也就是说,golang的defer管理使用了栈,先放进去的defer语句将稍后执行,下面的例子是使用golang中的defer的示例:
func tmp(r *int) {
* r += 10
}
func p1() {
fmt.Print("p1\n")
}
func p2() {
fmt.Print("p2\n")
}
func deferTest(i, j int) (r int){
fileName := "/Users/hujian06/github/goLang-demo/goFirst.go";
file, err := os.Open(fileName)
if err!= nil {
panic(err)
}
defer file.Close() // 1 defer
defer tmp(&r) // 2 defer
defer p1()
defer p2()
r = i + j
return r
}
r := deferTest(1, 2)
fmt.Print(r , "\n")
运行上面的代码,结果为13,而且p1和p2的输出顺序为p2->p1,这些结果充分说明了上面的结论,具体的细节可以自己测试一下。