最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go中并發(fā)控制的實現(xiàn)方式總結(jié)

 更新時間:2023年12月21日 09:15:23   作者:Serena  
在Go實際開發(fā)中,并發(fā)安全是老生常談的事情,在并發(fā)下,goroutine之間的存在數(shù)據(jù)資源等方面的競爭,為了保證數(shù)據(jù)一致性、防止死鎖等問題的出現(xiàn),在并發(fā)中需要使用一些方式來實現(xiàn)并發(fā)控制,本文給大家總結(jié)了幾種實現(xiàn)方式,需要的朋友可以參考下

Go的并發(fā)控制

在Go實際開發(fā)中,并發(fā)安全是老生常談的事情,在并發(fā)下,goroutine之間的存在數(shù)據(jù)資源等方面的競爭。

為了保證數(shù)據(jù)一致性、防止死鎖等問題的出現(xiàn),在并發(fā)中需要使用一些方式來實現(xiàn)并發(fā)控制。

并發(fā)控制的目的是確保在多個并發(fā)執(zhí)行的線程或進程中,對共享資源的訪問和操作能夠正確、有效地進行,并且避免出現(xiàn)競態(tài)條件和數(shù)據(jù)不一致的問題。

在Go中,可以通過以下幾種方式來實現(xiàn)并發(fā)控制:

1、channel

channel通道主要用于于goroutine之間通信和同步的機制。通過使用channel,可以在不同的goroutine之間進行數(shù)據(jù)的發(fā)送與接收,從而實現(xiàn)協(xié)調(diào)和控制并發(fā),以達到并發(fā)控制。

根據(jù)channel的類型,可以實現(xiàn)不同的并發(fā)控制效果:

無緩沖channel

當使用make初始化時,不指定channel的容量大小,即初始化無緩沖channel

當發(fā)送方向無緩沖channel發(fā)送消息數(shù)據(jù)時,如果發(fā)送后channel的數(shù)據(jù)未被接收方獲取,則當前goroutine會阻塞在發(fā)送語句中,直到有接收者準備好接收數(shù)據(jù)為止,即無緩沖通道要求發(fā)送操作和接收操作同時準備好才能完成通信。這樣做是確保了發(fā)送和接收的同步,避免了數(shù)據(jù)競爭和不確定性。

package main

import (
    "fmt"
    "time"
)

func main() {
    // 創(chuàng)建一個無緩沖通道
    ch := make(chan int)

    // 啟動一個 goroutine 接收數(shù)據(jù)
    go func() {
       time.Sleep(time.Second * 5)
       fmt.Println("等待接收數(shù)據(jù)")
       data := <-ch // 接收數(shù)據(jù)
       fmt.Println("接收到數(shù)據(jù):", data)
    }()

    fmt.Println("發(fā)送數(shù)據(jù)")
    // 發(fā)送數(shù)據(jù),由于匿名函數(shù)goroutine睡眠,無緩沖通道內(nèi)數(shù)據(jù)沒有g(shù)oroutine接收,因此會阻塞。5s后被接收則繼續(xù)執(zhí)行
    ch <- 100 
    time.Sleep(time.Second)
    fmt.Println("程序結(jié)束")
}
  • 在上述代碼中,創(chuàng)建了一個無緩沖通道 ch。然后在一個單獨的 goroutine 中啟動了一個接收操作,等待從通道 ch 中接收數(shù)據(jù)。

  • 接下來,在main goroutine中執(zhí)行發(fā)送操作,向通道 ch 發(fā)送數(shù)據(jù) 100。

  • 由于無緩沖通道的特性,當發(fā)送語句 ch <- 100 執(zhí)行時,由于沒有接收者準備好接收數(shù)據(jù)(單獨的goroutine處于5s睡眠),發(fā)送操作會被阻塞。

  • 接收方的 goroutine 在接收數(shù)據(jù)之前會一直等待。

  • 當接收方的 goroutine 準備好之后,發(fā)送操作完成,數(shù)據(jù)被成功發(fā)送并被接收方接收,然后程序繼續(xù)執(zhí)行后續(xù)語句,打印出相應(yīng)的輸出。

需要注意的是,在使用無緩沖channel時,如果沒有接收者,發(fā)送操作將會永久阻塞,可能會導(dǎo)致死鎖,因此在使用無緩沖通道時,需要確保發(fā)送和接收操作能夠匹配。

有緩沖channel

當使用make初始化時,可以指定channel的容量大小,即初始化有緩沖channel,通道的容量表示通道中最大能存放的元素數(shù)量

  • 當發(fā)送方發(fā)送數(shù)據(jù)到有緩存channel時,如果緩沖區(qū)滿了,則發(fā)送方會被阻塞直到有緩沖空間可以接收這個消息數(shù)據(jù);

  • 當接收方在有緩沖channel接收數(shù)據(jù)時,如果緩沖區(qū)為空,則接收方會被阻塞直到channel有數(shù)據(jù)可讀;

無論是緩存 channel 還是無緩沖 channel,都是并發(fā)安全的,即多個 goroutine 可以同時發(fā)送和接收數(shù)據(jù),而不需要額外的同步機制。

但是,由于緩存 channel 具有緩存空間,因此在使用時需要特別注意緩存空間的大小,避免過度消耗內(nèi)存或者發(fā)生死鎖等問題。

2、sync.WaitGroup

sync包中,sync.WaitGroup可以在并發(fā)goroutine之間起到執(zhí)行屏障的效果。WaitGroup提供了用于創(chuàng)建多個goroutine時,能夠等待多個并發(fā)執(zhí)行的代碼塊在達到WaitGroup顯示指定的同步條件后,才可以繼續(xù)執(zhí)行Wait的后續(xù)代碼。在使用sync.WaitGroup實現(xiàn)同步模式下,從而起到并發(fā)控制的效果。

在Go中,sync.WaitGroup類型提供了如下幾個方法:

方法名功能說明
func (wg * WaitGroup) Add(delta int)等待組計數(shù)器 + delta
(wg *WaitGroup) Done()等待組計數(shù)器-1
(wg *WaitGroup) Wait()阻塞直到等待組計數(shù)器變?yōu)?

示例:

package main

import (
    "fmt"
    "sync"
)

// 聲明全局等待組變量
var wg sync.WaitGroup

func printHello() {
    fmt.Println("Hello World")
    wg.Done() // 完成一個任務(wù)后,調(diào)用Done()方法,等待組減1,告知當前goroutine已經(jīng)完成任務(wù)
}

func main() {
    wg.Add(1) // 等待組加1,表示登記一個goroutine
    go printHello()
    fmt.Println("main")
    wg.Wait() // 阻塞當前goroutine,直到等待組中的所有g(shù)oroutine都完成任務(wù)
}

// 執(zhí)行結(jié)果
main
Hello World

3、sync.Mutex

sync.Mutex 是 Go 語言中的一個互斥鎖(Mutex)類型,用于實現(xiàn)對共享資源的互斥訪問。

互斥鎖是一種常見的并發(fā)控制機制,它能夠確保在同一時刻只有一個 goroutine 可以訪問被保護的資源,從而避免數(shù)據(jù)競爭和不確定的結(jié)果。

互斥鎖的作用可以有以下幾個方面:

  • 保護共享資源:當多個 goroutine并發(fā)訪問共享資源時,通過使用互斥鎖可以限制只有一個 goroutine 可以訪問共享資源,從而避免競態(tài)條件和數(shù)據(jù)不一致的問題。
  • 實現(xiàn)臨界區(qū):互斥鎖可以將一段代碼標記為臨界區(qū),只有獲取了鎖的 goroutine 才能執(zhí)行該臨界區(qū)的代碼,其他 goroutine 則需要等待解鎖,才能夠訪問臨界區(qū)內(nèi)的代碼塊。

互斥鎖的基本使用方式是,通過調(diào)用 Lock() 方法獲取鎖,執(zhí)行臨界區(qū)代碼,然后調(diào)用 Unlock() 方法釋放鎖。在獲取鎖之后,其他 goroutine 將會被阻塞,直到當前 goroutine 釋放鎖為止。Lock() 方法與Unlock() 底層的實現(xiàn)原理是使用原子操作來維護Mutexstate狀態(tài)。

sync.Mutex中,除了最基本的互斥鎖外,還提供讀寫鎖,在讀多寫少的場景下,相比互斥鎖性能上能夠有所提升。

channel 與 Mutex 對比例子

在自增操作x++中,該操作并非原子操作,因此在多個goroutine對全局變量x進行自增時,會出現(xiàn)數(shù)據(jù)覆蓋的情況,因此可以通過一些方法來實現(xiàn)并發(fā)控制,例如channel、互斥鎖原子操作。

可以對比一下channel互斥鎖在實現(xiàn)并發(fā)控制時的執(zhí)行時間:

  • 使用channel
package main

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

var x int64
var wg sync.WaitGroup

func main() {
    startTime := time.Now()
    ch := make(chan struct{}, 1)

    for i := 0; i < 10000; i++ {
       wg.Add(1)
       go func() {
          defer wg.Done()
          ch <- struct{}{}
          x++
          <-ch
       }()
    }
    wg.Wait()
    endTime := time.Now()
    fmt.Println(x)                      // 10000
    fmt.Println(endTime.Sub(startTime)) // 6.2933ms
}
  • 使用Mutex
package main

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

var x int64
var wg sync.WaitGroup
var lock sync.Mutex

func main() {
    startTime := time.Now()
    for i := 0; i < 10000; i++ {
       wg.Add(1)
       go func() {
          defer wg.Done()
          lock.Lock()
          x++
          lock.Unlock()
       }()
    }
    wg.Wait()
    endTime := time.Now()
    fmt.Println(x)                      // 10000
    fmt.Println(endTime.Sub(startTime)) // 3.0835ms
}

可以對比兩種方法的執(zhí)行時間,在啟動10000goroutine執(zhí)行10000次全局變量x++時,channel實現(xiàn)并發(fā)控制全局變量x++的執(zhí)行時間為6.2933ms(存在波動),而使用Mutex提供的互斥鎖實現(xiàn)并發(fā)控制全局變量x++的執(zhí)行時間為3.0835ms(存在波動),大約在兩倍左右,這是為什么呢?

原因在于channel的操作涉及到**goroutine之間的調(diào)度和上下文的切換**,而互斥鎖底層使用了Go的原子操作,執(zhí)行時間較短,因為互斥鎖的操作相對輕量,不涉及goroutine的調(diào)度以及上下文的切換。

在開發(fā)過程中,選擇使用通道還是互斥鎖取決于具體的場景與需求,并不是一定說使用鎖就好,需要根據(jù)實際的業(yè)務(wù)場景來進行選擇。如果需要更細粒度的控制和更高的并發(fā)性能,可以優(yōu)先考慮使用互斥鎖。

4、atomic原子操作

Go語言提供了原子操作用于對內(nèi)存中的變量進行同步訪問,避免了多個goroutine同時訪問同一個變量時可能產(chǎn)生的競態(tài)條件。

sync/atomic包提供了原子加操作、比較并交換等方法提供一系列原子操作,這些方法利用底層的原子指令,確保對內(nèi)存中的變量進行原子級別的訪問和修改,從而實現(xiàn)并發(fā)控制。

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

var x int64
var wg sync.WaitGroup

// 使用原子操作
func atomicAdd() {
    atomic.AddInt64(&x, 1)
    wg.Done()
}

func main() {
    for i := 0; i < 10000; i++ {
       wg.Add(1)
       go atomicAdd() // 原子操作add函數(shù)
    }
    wg.Wait()
    fmt.Println(x) // 10000
}

一些常用的原子操作函數(shù):

  • Add函數(shù):AddInt32AddInt64、AddUint32、AddUint64等方法,用于對變量進行原子加操作。
  • CompareAndSwap函數(shù):CompareAndSwapInt32、CompareAndSwapInt64CompareAndSwapUint32、CompareAndSwapUint64等,用于比較并交換操作,當舊值等于給定值時,將新值賦值到指定地址中。
  • Load函數(shù):LoadInt32、LoadInt64、LoadUint32、LoadUint64等,用于加載操作,返回指定地址中存儲的值。
  • Store函數(shù):StoreInt32、StoreInt64、StoreUint32、StoreUint64等,用于存儲操作,將給定的值存儲到指定地址中。
  • Swap函數(shù):SwapInt32、SwapInt64、SwapUint32SwapUint64等,用于交換操作,將指定地址中存儲的值和給定的值進行交換,并返回原值。

以上就是Go中并發(fā)控制的實現(xiàn)方式總結(jié)的詳細內(nèi)容,更多關(guān)于Go并發(fā)控制實現(xiàn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 對Golang import 導(dǎo)入包語法詳解

    對Golang import 導(dǎo)入包語法詳解

    今天小編就為大家分享一篇對Golang import 導(dǎo)入包語法詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • golang實現(xiàn)ftp實時傳輸文件的案例

    golang實現(xiàn)ftp實時傳輸文件的案例

    這篇文章主要介紹了golang實現(xiàn)ftp實時傳輸文件的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go中空接口的具體使用

    go中空接口的具體使用

    空接口是一種特殊的接口類型,它不包含任何方法,本文主要介紹了go中空接口的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2025-04-04
  • GO中公平鎖和非公平鎖的具體使用

    GO中公平鎖和非公平鎖的具體使用

    公平鎖和非公平鎖是計算機科學中的兩種鎖機制,它們主要用于多線程編程,以控制對共享資源的訪問,本文主要介紹了GO中公平鎖和非公平鎖的具體使用,感興趣的可以了解一下
    2024-08-08
  • 詳解go語言json的使用技巧

    詳解go語言json的使用技巧

    這篇文章主要介紹了詳解go語言json的使用技巧,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • Go 并發(fā)實現(xiàn)協(xié)程同步的多種解決方法

    Go 并發(fā)實現(xiàn)協(xié)程同步的多種解決方法

    這篇文章主要介紹了Go 并發(fā)——實現(xiàn)協(xié)程同步的多種解決方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-08-08
  • 深入理解Golang中WebSocket和WSS的支持

    深入理解Golang中WebSocket和WSS的支持

    本文主要介紹了深入理解Golang中WebSocket和WSS的支持,實現(xiàn)了Golang構(gòu)建WebSocket服務(wù)器和客戶端,并使用自簽名證書實現(xiàn)WSS的功能,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • Go設(shè)計模式之訪問者模式講解和代碼示例

    Go設(shè)計模式之訪問者模式講解和代碼示例

    訪問者是一種行為設(shè)計模式, 允許你在不修改已有代碼的情況下向已有類層次結(jié)構(gòu)中增加新的行為,本文將通過代碼示例給大家詳細的介紹一下Go設(shè)計模式之訪問者模式,需要的朋友可以參考下
    2023-08-08
  • Go?語言前綴樹實現(xiàn)敏感詞檢測

    Go?語言前綴樹實現(xiàn)敏感詞檢測

    這篇文章主要為大家介紹了Go語言前綴樹實現(xiàn)敏感詞檢測實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • go?colly?爬蟲實現(xiàn)示例

    go?colly?爬蟲實現(xiàn)示例

    這篇文章主要為大家介紹了go?colly?爬蟲實現(xiàn)示例,效果是根據(jù)輸入的瀏覽器cookie及excel必要行列號,從excel中讀取公司名稱,查詢公司法人及電話號碼。并寫回到excel中指定行
    2022-09-09

最新評論

乐陵市| 额敏县| 伊春市| 赣州市| 广元市| 襄城县| 绥化市| 应用必备| 五大连池市| 吉林市| 抚松县| 宜兰县| 合水县| 治县。| 阳曲县| 弥渡县| 永定县| 洛南县| 蒙山县| 齐河县| 龙泉市| 吴旗县| 慈溪市| 科技| 永胜县| 怀远县| 康定县| 巩留县| 井冈山市| 家居| 宁晋县| 诸暨市| 杭州市| 顺义区| 富宁县| 城步| 奇台县| 岳普湖县| 彩票| 饶平县| 沙河市|