首頁  >  文章  >  後端開發  >  Golang並發程式設計之Goroutines的同步與互斥機制詳解

Golang並發程式設計之Goroutines的同步與互斥機制詳解

PHPz
PHPz原創
2023-07-20 11:25:10964瀏覽

Golang並發程式設計之Goroutines的同步與互斥機制詳解

隨著多核心處理器的普及和電腦效能的不斷提高,如何充分利用多個處理器核心進行並行運算成為了開發人員面臨的一個重要問題。並發程式設計是解決這個問題的關鍵技術之一。在Golang中,Goroutines和Channels被廣泛用於實現並發程式設計。其中,Goroutines是一種輕量級的線程,可以實現高並發的任務處理。為了確保多個Goroutines之間的正確協作,同步與互斥機制起到了至關重要的作用。

一、Goroutines的基本概念
在Golang中,Goroutines是一種輕量級的線程,可以與其他Goroutines並發執行。與傳統執行緒相比,Goroutines的創建和銷毀花費的資源更少,並且可以更有效率地利用系統資源。

Goroutines透過關鍵字"go"來建立。範例程式碼如下:

package main

import (
    "fmt"
    "time"
)

func task1() {
    for i := 0; i < 5; i++ {
        fmt.Println("Task 1:", i)
        time.Sleep(time.Millisecond * 500)
    }
}

func task2() {
    for i := 0; i < 5; i++ {
        fmt.Println("Task 2:", i)
        time.Sleep(time.Millisecond * 500)
    }
}

func main() {
    go task1()
    go task2()

    time.Sleep(time.Millisecond * 3000)
}

在上述程式碼中,透過關鍵字"go"建立了兩個Goroutines,分別執行task1()task2()函數。在main()函數中,透過time.Sleep()函數等待3秒鐘,保證Goroutines有足夠的時間執行完畢。

二、Goroutines的同步與互斥機制
在實際的並發程式設計中,多個Goroutines可能需要共用某些資源。這時候就需要透過同步與互斥機制來確保資源的正確存取。

  1. 同步
    在Golang中,常用的同步機制有WaitGroup、Mutex和RWMutex。

1.1 WaitGroup
WaitGroup用於等待一組Goroutines的執行完成。它的函數類似於Java中的CountDownLatch。範例程式碼如下:

package main

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

func task(i int, wg *sync.WaitGroup) {
    defer wg.Done()

    fmt.Println("Task", i)
    time.Sleep(time.Millisecond * 500)
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go task(i, &wg)
    }

    wg.Wait()
    fmt.Println("All tasks finished")
}

在上述程式碼中,透過sync.WaitGroup建立了一個等待群組wg。在每個Goroutine的執行前呼叫wg.Add(1)將等待群組計數器加1,表示有一個任務需要等待。在每個Goroutine執行完畢後呼叫wg.Done()將等待群組計數器減1,表示一個任務已完成。最後,透過wg.Wait()等待所有任務執行完成。

1.2 Mutex
Mutex是一種互斥鎖,用來保護共享資源在同一時間只能被一個Goroutine存取。範例程式碼如下:

package main

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

var count int
var mutex sync.Mutex

func task(i int, wg *sync.WaitGroup) {
    defer wg.Done()

    mutex.Lock()
    defer mutex.Unlock()

    count++
    fmt.Println("Task", i, "count:", count)
    time.Sleep(time.Millisecond * 500)

    mutex.Lock()
    defer mutex.Unlock()

    count--
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go task(i, &wg)
    }

    wg.Wait()
    fmt.Println("All tasks finished")
}

在上述程式碼中,透過sync.Mutex建立了一個互斥鎖mutex。在每個Goroutine中,透過呼叫mutex.Lock()mutex.Unlock()的配對來保護共享資源的存取。在實際的應用中,可以將需要保護的共享資源存放在結構體中,透過結構體中的互斥鎖來控制對共享資源的存取。

  1. 互斥
    除了同步外,有時候還需要透過互斥來確保某段程式碼在同一時間只能被一個Goroutine執行。在Golang中,常用的互斥機制有Once和Mutex。

2.1 Once
Once用於保證某段程式碼在程式執行期間​​只會執行一次。範例程式碼如下:

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

func task() {
    fmt.Println("Task executed")
}

func main() {
    for i := 0; i < 5; i++ {
        once.Do(task)
    }
}

在上述程式碼中,透過sync.Once建立了一個Once物件once。在每個Goroutine中,透過呼叫once.Do(task)來保證task()函數在整個程式運行期間只會執行一次。

2.2 Mutex
Mutex也可以用來實現互斥。範例程式碼如下:

package main

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

var count int
var mutex sync.Mutex

func task(i int, wg *sync.WaitGroup) {
    defer wg.Done()

    mutex.Lock()
    defer mutex.Unlock()

    fmt.Println("Task", i)
    time.Sleep(time.Millisecond * 500)
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go task(i, &wg)
    }

    wg.Wait()
    fmt.Println("All tasks finished")
}

在上述程式碼中,透過呼叫mutex.Lock()mutex.Unlock()來保證在同一時間只能有一個Goroutine執行task()函數,並存取共享資源。

總結
透過本文的介紹,我們了解了Golang並發程式設計中Goroutines的同步與互斥機制。在實際的應用中,同步與互斥機制是確保多個Goroutines之間正確協作的關鍵。合理地使用WaitGroup、Mutex和RWMutex等同步與互斥機制,可以確保共享資源的正確訪問,從而實現高效的並發編程。

以上是Golang並發程式設計之Goroutines的同步與互斥機制詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn