第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會有你想問的

如何使變量線程安全

如何使變量線程安全

Go
至尊寶的傳說 2023-04-24 16:25:06
我是 Go 的新手,我需要使變量線程安全。我知道在 java 中你可以只使用關(guān)鍵字synchronized,但在 go 中似乎不存在這樣的東西。有什么方法可以同步變量嗎?
查看完整描述

1 回答

?
白衣非少年

TA貢獻(xiàn)1155條經(jīng)驗(yàn) 獲得超0個(gè)贊

synchronized在 Java 中是一種只允許單個(gè)線程執(zhí)行代碼塊的方法(在任何給定時(shí)間)。

在 Go 中有許多結(jié)構(gòu)可以實(shí)現(xiàn)這一點(diǎn)(例如互斥鎖、通道、等待組、原語sync/atomic),但 Go 的格言是:“不要通過共享內(nèi)存進(jìn)行通信;相反,通過通信共享內(nèi)存?!?/em>

因此,與其鎖定和共享變量,不如嘗試不這樣做,而是在 goroutine 之間傳遞結(jié)果,例如使用通道(這樣您就不必訪問共享內(nèi)存)。

當(dāng)然,在某些情況下,最簡單、直接的解決方案是使用互斥鎖來保護(hù)多個(gè) goroutine 對變量的并發(fā)訪問。在這種情況下,您可以這樣做:

var (

? ? mu? ? ? ? sync.Mutex

? ? protectMe int

)


func getMe() int {

? ? mu.Lock()

? ? me := protectMe

? ? mu.Unlock()

? ? return me

}


func setMe(me int) {

? ? mu.Lock()

? ? protectMe = me

? ? mu.Unlock()

}

上述解決方案可以在幾個(gè)方面進(jìn)行改進(jìn):

  • 使用sync.RWMutexinstead of?sync.Mutex,以便getMe()可以鎖定為只讀,這樣多個(gè)并發(fā)讀者就不會互相阻塞。

  • 在(成功)鎖定之后,建議使用 解鎖defer,這樣如果后續(xù)代碼中發(fā)生錯(cuò)誤(例如運(yùn)行時(shí)恐慌),互斥體仍將被解鎖,避免資源泄漏和死鎖。盡管此示例非常簡單,但不會發(fā)生任何不良情況,也不能保證無條件地使用延遲解鎖。

  • 最好讓互斥體靠近它應(yīng)該保護(hù)的數(shù)據(jù)。因此,“包裝”protectMe及其mu在結(jié)構(gòu)中是個(gè)好主意。而且如果我們這樣做,我們也可以使用嵌入,因此鎖定/解鎖變得更加方便(除非必須不公開此功能)。

因此,上述示例的改進(jìn)版本可能如下所示(在Go Playground上嘗試):

type Me struct {

? ? sync.RWMutex

? ? me int

}


func (m *Me) Get() int {

? ? m.RLock()

? ? defer m.RUnlock()

? ? return m.me

}


func (m *Me) Set(me int) {

? ? m.Lock()

? ? m.me = me

? ? m.Unlock()

}


var me = &Me{}


func main() {

? ? me.Set(2)

? ? fmt.Println(me.Get())

}

此解決方案還有另一個(gè)優(yōu)點(diǎn):如果您需要 的多個(gè)值Me,它會自動為每個(gè)值具有不同的、單獨(dú)的互斥鎖(我們的初始解決方案需要為每個(gè)新值手動創(chuàng)建單獨(dú)的互斥鎖)。


雖然這個(gè)例子是正確有效的,但可能不實(shí)用。因?yàn)楸Wo(hù)單個(gè)整數(shù)并不真正需要互斥體。我們可以使用sync/atomic包實(shí)現(xiàn)相同的目的:


var protectMe int32


func getMe() int32 {

? ? return atomic.LoadInt32(&protectMe)

}


func setMe(me int32) {

? ? atomic.StoreInt32(&protectMe, me)

}

這個(gè)解決方案更短、更干凈、更快。如果您的目標(biāo)只是保護(hù)單個(gè)值,則首選此解決方案。如果您應(yīng)該保護(hù)的數(shù)據(jù)結(jié)構(gòu)更復(fù)雜,atomic甚至可能不可行,那么使用互斥量可能是合理的。

現(xiàn)在在展示了共享/保護(hù)變量的例子之后,我們還應(yīng)該給出一個(gè)例子,我們應(yīng)該實(shí)現(xiàn)什么目標(biāo)來實(shí)現(xiàn)“不要通過共享內(nèi)存進(jìn)行通信;相反,通過通信共享內(nèi)存”。

情況是你有多個(gè)并發(fā)的 goroutines,你使用一個(gè)變量來存儲一些狀態(tài)。一個(gè) goroutine 更改(設(shè)置)狀態(tài),另一個(gè) goroutine 讀?。ǐ@?。顟B(tài)。要從多個(gè) goroutine 訪問此狀態(tài),必須同步訪問。

這個(gè)想法是不要有這樣的“共享”變量,而是一個(gè) goroutine 設(shè)置的狀態(tài),它應(yīng)該“發(fā)送”它,而另一個(gè) goroutine 會讀取它,它應(yīng)該是狀態(tài)“發(fā)送到”(或者換句話說,另一個(gè) goroutine 應(yīng)該接收更改后的狀態(tài))。所以沒有共享狀態(tài)變量,取而代之的是2 個(gè) goroutines 之間的通信。Go 為這種“協(xié)程間”通信提供了出色的支持:channels。對通道的支持內(nèi)置于語言中,有send statements,receive operators和其他支持(例如你可以循環(huán)在通道上發(fā)送的值)。

讓我們看一個(gè)實(shí)際/現(xiàn)實(shí)生活中的例子:“經(jīng)紀(jì)人”。代理是一個(gè)實(shí)體,其中“客戶端”(goroutines)可以訂閱接收消息/更新,并且代理能夠向訂閱的客戶端廣播消息。在一個(gè)有大量客戶端隨時(shí)可能訂閱/取消訂閱的系統(tǒng)中,并且可能需要隨時(shí)廣播消息,以安全的方式同步所有這些將很復(fù)雜。明智地使用通道,這個(gè)代理實(shí)現(xiàn)相當(dāng)干凈和簡單。該實(shí)現(xiàn)對于并發(fā)使用是完全安全的,支持“無限”客戶端,并且不使用單個(gè)互斥鎖或共享變量,僅使用通道。


查看完整回答
反對 回復(fù) 2023-04-24
  • 1 回答
  • 0 關(guān)注
  • 128 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號