Golang sync包 簡述

Sync包簡述

1. 什么是Sync包?

Package sync provides basic synchronization primitives such as mutual exclusion locks. Other than the Once and WaitGroup types, most are intended for use by low-level library routines. Higher-level synchronization is better done via channels and communication.

Values containing the types defined in this package should not be copied.

這句話大意是說:
Sync包同步提供基本的同步原語,如互斥鎖。 除了Once和WaitGroup類型之外,大多數(shù)類型都是供低級庫例程使用的。 通過Channel和溝通可以更好地完成更高級別的同步。并且此包中的值在使用過后不要拷貝。

從描述中可以看到的是,golang 并不推薦這個包中的大多數(shù)并發(fā)控制方法,但還是提供了相關(guān)方法,主要原因是golang中提倡以共享內(nèi)存的方式來通信:

不要以共享內(nèi)存的方式來通信,作為替代,我們應(yīng)該以通信的手段來共享內(nèi)存

共享內(nèi)存的方式使得多線程中的通信變得簡單,但是在并發(fā)的安全性控制上將變得異常繁瑣。
正確性不是我們唯一想要的,我們想要的還有系統(tǒng)的可伸縮性,以及可理解性,我覺得這點非常重要,比如現(xiàn)在廣泛使用的Raft算法。

2. 包中的Type

包中主要有: Locker, Cond, Map, Mutex, Once, Pool,
RWMutex, WaitGroup

type Locker interface {
        Lock()
        Unlock()
}
type Cond struct {
        // L is held while observing or changing the condition
        L Locker
}

3. 什么是鎖,為什么需要鎖?

鎖是sync包中的核心,他主要有兩個方法,加鎖和解鎖。
在單線程運行的時候程序是順序執(zhí)行的,程序?qū)?shù)據(jù)的訪問也是:
讀取 => 一頓操作(加減乘除之類的) => 寫回原地址
但是一旦程序中進行了并發(fā)編程,也就是說,某一個函數(shù)可能同時被不同的線程執(zhí)行的時候,以時間為維度會發(fā)生以下情況:

可以看到的是,A地址的數(shù)字被執(zhí)行了兩次自增,若A=5,我們在執(zhí)行完成后預(yù)期的A值是7,但是在這種情況下我們得到的A卻是6,bug了~
還有很多類似的并發(fā)錯誤,所以才有鎖的引入。若是我們在線程2讀取A的值的時候?qū)進行加鎖,讓線程2等待,線程1執(zhí)行完成之后在執(zhí)行線程2,這樣就能夠保證數(shù)據(jù)的正確性。但是正確性不是我們唯一想要的。

4 寫更優(yōu)雅的代碼

在很多語言中我們經(jīng)常為了保證數(shù)據(jù)安全正確,會在并發(fā)的時候?qū)?shù)據(jù)加鎖

Lock()
doSomething()
Unlock()

Golang在此包中也提供了相關(guān)的鎖,但是標明了"most are intended for use by low-level library routines" 所以我這里只對 Once and WaitGroup types做簡述。

5.Once 對象

Once 是一個可以被多次調(diào)用但是只執(zhí)行一次,若每次調(diào)用Do時傳入?yún)?shù)f不同,但是只有第一個才會被執(zhí)行。

func (o *Once) Do(f func())

    var once sync.Once
    onceBody := func() {
        fmt.Println("Only once")
    }
    done := make(chan bool)
    for i := 0; i < 10; i++ {
        go func() {
            once.Do(onceBody)
            done <- true
        }()
    }
    for i := 0; i < 10; i++ {
        <-done
    }

如果你執(zhí)行這段代碼會發(fā)現(xiàn),雖然調(diào)用了10次,但是只執(zhí)行了1次。BTW:這個東西可以用來寫單例。

6. WaitGroup

func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()

wait group 用來等待一組goroutines的結(jié)束,在主Goroutine里聲明,并且設(shè)置要等待的goroutine的個數(shù),每個goroutine執(zhí)行完成之后調(diào)用 Done,最后在主Goroutines 里Wait即可。下面是個官方的例子:

var wg sync.WaitGroup
var urls = []string{
        "http://www.golang.org/",
        "http://www.google.com/",
        "http://www.somestupidname.com/",
}
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()

7. 簡述

Golang中高級的并發(fā)可以通過channel來實現(xiàn),這是golang所倡導(dǎo)的,但是go也提供了鎖等先關(guān)操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容