golang之路-并发编程小记(1)

学习了go的基本的并发变成模式,思路就是一个用通信来共享数据,而并不是像java一样共享内存来通讯。go采用了用channel来传递消息,每一个协程持有一个信道,当信道可用时便可以读写数据,各信道间的处理数据互不影响。回想一下java中的并发编程,通常我们是因为操作一个数据而采用多线程并发访问,比较明显的是更新cache中的key对应的value.

让我更是欢喜的时在golang中提供了sync.Once这个神器,从此做系统级的开关不再苦恼,天然的保证了就算多个协程并发的情况下也只有一个协程执行once.Do(func()),其他的协程阻塞。你再想想java里面完成一个系统级初始化,做到并发安全且一次,你要搞一个boolean、再搞把锁,再写逻辑,神啊想想头都大了。

下面是我的小尝试,你可以试试

 

 
  
package main

import (
	"fmt"
	"sync"
	"time"
)

var counter int = 0

func main() {
	chls := make([]chan int, 10)
	for i := 0; i < 10; i++ {

		chls[i] = make(chan int)
		go addCounter(chls[i])

	}

	for _, val := range chls {
		counter += <-val
	}

	fmt.Println("---结果是:", counter)

	//设置一个超时的chan,没有阻塞读超时,写超时,可由程序创建chan来判定是否有超时写入
	timeout := make(chan bool, 1)
	subChn := chls[:2]
	for i := 0; i < 2; i++ {
		go timeoutAdd(i, subChn[i], timeout)
	}

	countDonw := 2
	for {
		select {
		case <-subChn[0]:
			fmt.Println("not time out ")
			countDonw--
		case <-timeout:
			fmt.Println("time out ")
			countDonw--

		}

		if countDonw <= 0 {
			break
		}
	}

	//关闭channel
	for idx, ch := range chls {
		close(ch)
		_, ok := <-ch
		if !ok {
			fmt.Println("close channel ", idx)
		}
	}

	// //单向读channel
	// onedirchl := make(<-chan int)
	// //我来试试写操作,会有什么现象呢
	// //go 会报invalid operation: onedirchl <- 1 (send to receive-only type <-chan int)
	// onedirchl <- close(onedirchl)

	//全局唯一性操作,大爱啊,想想java在做系统初始化只需要执行一次并且是多线程并发情况下的代码怎么写?
	//Lock ?全局boolean的开关,我的神啊,复杂

	var once sync.Once

	completeChan := []chan bool{make(chan bool, 1), make(chan bool, 1)}

	//注意啊这里一定要传入指针,不然会是once的一个副本
	go initConifg(&once, func() {
		fmt.Println("我是第一个初始化的channel!")
		completeChan[0] <- true
	})

	go initConifg(&once, func() {
		fmt.Println("我是第二个完成初始化的channel!")
		completeChan[1] <- true
	})

	for _, ch := range completeChan {
		<-ch
		close(ch)
	}

}

func initConifg(once *sync.Once, handler func()) {
	once.Do(func() {
		time.Sleep(5e9)
		fmt.Println("我这是初始化!,我等待了5S完成")
	})

	handler()

}

func timeoutAdd(index int, chl chan int, timeout chan bool) {
	if index%2 != 0 {
		time.Sleep(5e9)
		fmt.Println("模拟超时了")
		timeout <- true
	} else {
		fmt.Println("正常输出..")
		chl <- 1
	}

}

func addCounter(chl chan int) {
	chl <- 1
	fmt.Println("countting")

}
 

 

你可能感兴趣的:(golang)