美文网首页
【Go 精选】并发编程实战 - 协程

【Go 精选】并发编程实战 - 协程

作者: 熊本极客 | 来源:发表于2022-12-24 20:51 被阅读0次

1.协程的概念

Go 应用程序并发处理的部分被称作 goroutines(协程),可以进行更有效的并发运算。协程是抽象出来的线程,并在用户空间进行协程管理,减少内核的压力。

image.png

2.实战

2.1 协程的实战

协程是通过使用关键字 go 调用一个函数或者方法来实现的,即在当前的计算过程中开始一个同时进行的函数,在相同的地址空间中并且分配了独立的栈,例如:go sum(bigArray)

package goroutine

import (
    "fmt"
    "time"
)

func longWait() {
    fmt.Println("Beginning longWait()")
    time.Sleep(5 * 1e9) // sleep for 5 seconds
    fmt.Println("End of longWait()")
}

func shortWait() {
    fmt.Println("Beginning shortWait()")
    time.Sleep(2 * 1e9) // sleep for 2 seconds
    fmt.Println("End of shortWait()")
}
package goroutine

import (
    "fmt"
    "testing"
    "time"
)

func TestGoroutine(t *testing.T) {
    fmt.Println("In goroutine()")
    go longWait()
    go shortWait()
    fmt.Println("About to sleep in goroutine()")
    // sleep works with a Duration in nanoseconds (ns) !
    time.Sleep(10 * 1e9)
    fmt.Println("At the end of goroutine()")
}

2.2 互斥锁的实战

如果使用了互斥锁,可以保证每次进入临界区的只有一个 goroutine,一个 goroutine 执行完后,另一个 goroutine 才能进入临界区执行,最终就实现了并发控制。

image.png
package goroutine

import (
    "fmt"
    "sync"
    "testing"
)

func TestGoroutineWg(t *testing.T) {
    var lock sync.Mutex
    var count int
    var wg sync.WaitGroup

    wg.Add(1) 
    go func() {
        defer wg.Done()
        lock.Lock()
        defer lock.Unlock()
        count++
        fmt.Println("count1=", count)
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()
        lock.Lock()
        defer lock.Unlock()
        count--
        fmt.Println("count2=", count)
    }()

    wg.Wait()
    fmt.Println("count3=", count)
}
type WaitGroup struct {
 noCopy noCopy
 state1 [3]uint32  #代表三个字段:counter, waiter, sema
}

● counter:计数器,每次经过wg.Add(X)或者wg.Done()后的值
● waiter:调用wg.Wait()的数量,也就是等待者的数量
● sema:信号量,用于换醒Wait()函数
退出 WaitGroup 的条件:counter == 0

Add(n)
① 更新 counter 的值。counter += n
② 判断当前 counter > 0 || waiter == 0,满足条件,说明当前还有groutine没有执行完,直接返回。
③ 走到这一步,说明 counter == 0 && waiter != 0,说明groutine全部执行了 Done() 方法,换醒执行了wg.Wait()的协程,将state设置成0,返回。

Wait()
① 判断 counter == 0,如果为 true,说明 groutine 已经全部执行了 Done() 方法,Wait Done。
② 此时 counter != 0,说明需要阻塞当前协程的执行,执行下面的 CAS 判断
③ CAS 判断 wg.state 有没有被改变,没有则更新 wg.state 为1,当前协程进入 sleep 状态,等待信号量换醒。换醒后继续循环判断,此时 counter==0,直接 wait done。
④ CAS判断 wg.state 有没有被改变,有则继续循环判断。继续判断 counter

Done()
Done 的实现就是 Add. 只不过我们常规用法 wg.Add(1) 是加 1 ,wg.Done() 是减 1,即 wg.Done() 可以用 wg.Add(-1) 来代替。

相关文章

网友评论

      本文标题:【Go 精选】并发编程实战 - 协程

      本文链接:https://www.haomeiwen.com/subject/qhcqoltx.html