0
点赞
收藏
分享

微信扫一扫

go语言并发编程(二)

代码敲到深夜 2022-01-26 阅读 38

一、除了使用通道channel来实现同步外,还可以通过Mutex互斥锁的方式来实现。

当多个资源来访问资源时,要实现程序的原子性。 如果没有加锁来实现以下程序。

加入WaitGroup还是无法实现程序的原子性

var i int = 100
var wg sync.WaitGroup

func add(){
	defer wg.Done()
	i += 1
	fmt.Printf("i++ : %v\n", i)
}

func sub(){
	defer wg.Done()
	i -= 1
	fmt.Printf("i-- : %v\n", i)
}

func main(){
	for i:=0; i<100; i++ {
		wg.Add(1)
		go add() // 子协程1
		wg.Add(1)
		go sub() // 子协程2
	}
	fmt.Printf("最后i的值为: %v\n", i)
}

而加入互斥锁后,可以保证程序的原子性执行

二、 并发编程select switch

  1. select 是 Go语言中的一个控制结构,类似于switch ,用于处理异步IO操作,select会监听case语句中的channel的读写操作,当case中channel 读写操作为非阻塞情况下,将会触发相应的操作。
  1. 如果有多个case语句可以执行,select会随机公平的选出一个执行,其他不会执行
  2. 如果没有可运行的case语句,且有default语句,那么最后会执行default语句
  3. 如果没有可运行的case语句,且没有default语句,select将会被阻塞,直到某个case通信可以执行
func main(){
	var chanInt = make(chan int)
	var chanString = make(chan string)
	go func(){
		chanInt <- 100
		chanString <- "hello"
		close(chanInt)
		close(chanString)
	}()

	for{
		select{
		case r:= <- chanInt:
			fmt.Printf("chanInt: %v\n", r)
		case r:= <- chanString:
			fmt.Printf("chanString: %v\n", r)
		default:
			fmt.Printf("end......")
		}
		time.Sleep(time.Second)
	}
}

三、 并发编程Timer / Ticker

Timer实现定时器的功能,只能执行一次,内部主要通过通道channel来实现。
Ticker可以周期的执行 , 方法创建和运用和Timer相同,只是Ticker可以通过循环来周期执行,使用ticker.Stop()来停止。

Timer(两种)创建方法:

fmt.Printf("time.Now() : %v\n", time.Now()) 
// (1)NewTimer
timer := time.NewTimer(time.Second * 2) //定时2秒后执行
t1 := <-timer.C // .C 阻塞的直到时间到达
fmt.Printf("t1 : %v\n", t1)
// 最后相互差两秒


// (2)也可以直接等待
<-timer.C  // == time.Sleep(time.Second * 2)

// (3)或者 After
<-time.After(time.Second * 2)

四、 并发编程原子操作

atomic.AddInt64(&i, 1) // +1 操作
atomic.AddInt64(&i, 1) // -1 操作

atomic.LoadInt64(&i) // 读i操作
atomic.StoreInt64(&j, 100) // 写操作
举报

相关推荐

0 条评论