Go Goroutine协程

并发和并行的区别

  1. 并发是指一个处理器同时处理多个任务。
  2. 并行是指多个处理器或者是多核的处理器同时处理多个不同的任务。

并发意思就是一个时间段一个处理器处理任务


并行是多个处理器处理任务

线程与协程的区别

  1. 一个线程可以多个协程,一个进程也可以单独拥有多个协程。

  2. 线程进程都是同步机制,而协程则是异步。

  3. 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。

  4. 协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程

Goroutine

只需在函数调⽤语句前添加 go 关键字,就可创建并发执⾏单元。

简单实例

package concurrence

import (
   "fmt"
   "time"
)

func hello(i int) {
   println("hello goroutine : " + fmt.Sprint(i))
}

func HelloGoRoutine() {
   for i := 0; i < 5; i++ {
      go func(j int) {
         hello(j)
      }(i)
   }
   time.Sleep(time.Second)
}
复制代码

改进实例

sync.WaitGroup也是一个经常会用到的同步原语,它的使用场景是在一个goroutine等待一组goroutine执行完成。

package main

import (
   "fmt"
   "sync"
)

func hello(i int) {
   println("hello goroutine : " + fmt.Sprint(i))
}

func HelloGoRoutine(wg *sync.WaitGroup) {
   defer wg.Done()
   for i := 0; i < 5; i++ {
         hello(i)
   }
}

func main() {
   wg :=sync.WaitGroup{}

   wg.Add(1)
   HelloGoRoutine(&wg)

   wg.Wait()

   fmt.Println("i我在最后")

}
复制代码

Channel

如果说goroutine是Go并发的执行体,那么"通道"就是他们之间的连接。
通道可以让一个goroutine发送特定的值到另外一个goroutine的通信机制 简而言之Channel可以实现携程之间的值传递
详细文章
(47条消息) channel 的基本使用_chengqiuming的博客-CSDN博客_channel://ltmh131

package main

func CalSquare() {
   src := make(chan int)
   dest := make(chan int, 3)
   go func() {
      defer close(src)
      for i := 0; i < 10; i++ {
         src <- i
      }
   }()
   go func() {
      defer close(dest)
      for i := range src {
         dest <- i * i
      }
   }()
   for i := range dest {
      //复杂操作
      println(i)
   }
}
复制代码

并发安全

互斥锁

package main
 
import (
	"fmt"
	"sync"
)
 
var x int64
var wg sync.WaitGroup
var lock sync.Mutex
 
func add() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock()
		x++
		lock.Unlock()
	}
}
func main() {
	wg.Add(2)
	go add()
	go add()
	wg.Wait()
	fmt.Println(x)
}
复制代码

这样使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待锁;当互斥锁释放后,等待的goroutine才可以获取锁进入临界区,多个goroutine同时等待一个锁时,唤醒策略是随机的。

读写互斥锁
当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的,这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。

读写锁分为两种:读锁和写锁。当一个goroutine获取读锁之后,其他的goroutine如果获取读锁则会继续获取锁,如果是获取写锁就会等待;当一个goroutine获取写锁之后,其他的goroutine无论是读锁还是写锁都会等待

package main
 
import (
	"fmt"
	"sync"
	"time"
)
 
var x int64
var wg sync.WaitGroup
var lock sync.Mutex
var rwlock sync.RWMutex
 
func write() {
	defer wg.Done()
	// lock.Lock() //加互斥锁
	rwlock.Lock() //加写锁
	x++
	time.Sleep(time.Microsecond * 10)
	rwlock.Unlock() //解写锁
	// lock.Unlock() //解互斥锁
}
 
func read() {
	defer wg.Done()
	// lock.Lock()  //加互斥锁
	rwlock.RLock() //加读锁
	time.Sleep(time.Millisecond)
	rwlock.RUnlock() //解读锁
	// lock.Unlock() //解互斥锁
}
 
func main() {
	start := time.Now()
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go write()
	}
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go read()
	}
	wg.Wait()
	end := time.Now()
	fmt.Println(end.Sub(start))
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

owensweat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值