golang协程同步的几种方法

golang协程同步的几种方法,第1张

概述目录 golang协程同步的几种方法 协程概念简要理解 为什么要做同步 协程的几种同步方法 Mutex channel WaitGroup golang协程同步的几种方法 本文简要介绍下go中协程的几种同步方法。 协程概念简要理解 协程类似线程,是一种更为轻量级的调度单位,但协程还是不同于线程的,线程是系统级实现的,常见的调度方法是时间片轮转法,如每隔10ms切换一个线程执行。 协程则是应用软件级

目录

golang协程同步的几种方法 协程概念简要理解 为什么要做同步 协程的几种同步方法 Mutex channel WaitGroup golang协程同步的几种方法

本文简要介绍下go中协程的几种同步方法。

协程概念简要理解

协程类似线程,是一种更为轻量级的调度单位,但协程还是不同于线程的,线程是系统级实现的,常见的调度方法是时间片轮转法,如每隔10ms切换一个线程执行。

协程则是应用软件级实现,它和线程的原理差不多,当一个协程调度到另一个协程时,将上一个协程的上下文信息压入堆栈,来回切换。一个线程可以跑很多个协程,由这个线程来调度协程的切换,如果是C/C++的话底层就能通过select/poll/epoll来做,例如微信后台的开源libco库。

golang协程底层不是C,纯go实现,golang的协程应该是目前各类有协程概念的语言中实现的最完整和成熟的,调度是基于GPM模型实现的,有兴趣可以去了解下,这里不扯远了,下面看看协程的同步。

为什么要做同步

至于为什么需要同步呢,类似线程要做同步差不多,现在的cpu都是多核,假设一核一个线程同时一起访问同一块内存中的数据吗,那么可能上一ns第一个线程刚把数据从寄存器拷贝到内存,第二个线程马上又把此数据用它修改的值给覆盖了,这样共享数据变会乱套。

举个例子 :

用2个协程序并发各自增一个全局变量100 0000 次

package main import(    "fmt"    "time")var share_cnt uint64 = 0func incrShareCnt() {    for i:=0; i < 1000000; i++ {        share_cnt++    }        fmt.Println(share_cnt)}func main()  {        for i:=0; i < 2; i++ {        go incrShareCnt()    }    time.Sleep(1000*time.Second)}

运行4次 , 可以看到我们虽然自增了200 0000次,但没有一个输出200 0000的结果.

协程的几种同步方法 Mutex

互斥锁,可以创建为其他结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。

package mainimport(    "fmt"    "time"    "sync")var share_cnt uint64 = 0var lck sync.Mutexfunc incrShareCnt() {    for i:=0; i < 1000000; i++ {        lck.Lock()        share_cnt++        lck.Unlock()    }        fmt.Println(share_cnt)}func main()  {        for i:=0; i < 2; i++ {        go incrShareCnt()    }    time.Sleep(1000*time.Second)}

channel

使用golang的channel,下面一个典型的生产消费模型

package main import(    "fmt"    "time"    "strconv")func main() {    msg_chan := make(chan string)    done     := make(chan bool)    i := 0    go func() {        for  {            i++            time.Sleep(1*time.Second)            msg_chan <- "on message"            <- done        }    }()    go func() {        for {            select {            case msg := <- msg_chan :                i++                fmt.Println(msg + " " + strconv.Itoa(i))                time.Sleep(2*time.Second)                done <- true            }        }    }()    time.Sleep(20*time.Second)}

WaitGroup

sync包中的WaitGroup可用等待一组协程的结束。
父协程通过Add方法来设定应等待的线程的数量。
每个被等待的协程在结束时调用Done方法。
同时,主协程里调用Wait方法阻塞至所有线程结束。

package mainimport(    "sync"    "net/http")var wg sync.WaitGroupvar urls = []string{    "http://www.baIDu.com/","http://www.taobao.com/","http://www.tianmao.com/",}func main() {for _,url := range urls {    // Increment the WaitGroup counter.    wg.Add(1)    // Launch a goroutine to fetch the URL.    go func(url string) {        // Decrement the counter when the goroutine completes.        defer wg.Done()        // Fetch the URL.        http.Get(url)    }(url)}// Wait for all http fetches to complete.wg.Wait()}
总结

以上是内存溢出为你收集整理的golang协程同步的几种方法全部内容,希望文章能够帮你解决golang协程同步的几种方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1266298.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存