欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go 阻塞的實(shí)現(xiàn)示例

 更新時(shí)間:2024年05月15日 09:47:03   作者:比豬聰明  
Go語言提供了多種同步和通信機(jī)制,可以用于實(shí)現(xiàn)阻塞的效果,本文主要介紹了Go 阻塞的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下

阻塞 

在Go語言中,阻塞通常指的是一個(gè)goroutine(輕量級(jí)線程)在等待另一個(gè)goroutine完成操作(如I/O操作、channel通信等)時(shí),暫時(shí)停止執(zhí)行的現(xiàn)象。Go語言提供了多種同步和通信機(jī)制,可以用于實(shí)現(xiàn)阻塞的效果。

使用 Channel 實(shí)現(xiàn)阻塞

Channel 是Go語言中的一個(gè)核心特性,用于在goroutines之間進(jìn)行通信。通過channel,你可以實(shí)現(xiàn)阻塞等待數(shù)據(jù)或命令。

package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan struct{})
	go func() {
		fmt.Println("業(yè)務(wù)處理~~~")
		time.Sleep(2 * time.Second)
		fmt.Println("業(yè)務(wù)處理完成~~~")
		close(c) // 關(guān)閉channel,通知工作完成
	}()

	<-c // 阻塞等待channel關(guān)閉
	fmt.Println("處理其他業(yè)務(wù)~~~")
}

使用 WaitGroup 實(shí)現(xiàn)阻塞

WaitGroup 是Go語言中用于同步一組并發(fā)操作的另一個(gè)工具。它通過計(jì)數(shù)器來跟蹤完成的操作數(shù)量。

package main

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

func main() {
	var wg sync.WaitGroup //控制并發(fā)組

	doWork := func(i int) {
        // wg.Done(): 表示一個(gè)事件已經(jīng)完成。它等價(jià)于 wg.Add(-1),但更明確地表達(dá)了“完成一個(gè)任務(wù)”的意圖,并且在使用上更安全,因?yàn)樗粫?huì)導(dǎo)致計(jì)數(shù)變?yōu)樨?fù)數(shù)(如果已經(jīng)到達(dá)零,則會(huì)panic)。
		defer wg.Done() // 當(dāng)函數(shù)返回時(shí),通知WaitGroup一個(gè)操作已完成相當(dāng)于wg.Add(-1)
		fmt.Println("處理業(yè)務(wù)~~~" + strconv.Itoa(i))
		time.Sleep(2 * time.Second)
		fmt.Println("業(yè)務(wù)處理完成~~~" + strconv.Itoa(i))
	}

	for i := 0; i < 5; i++ {
		wg.Add(1)    // 增加WaitGroup的計(jì)數(shù)器
		go doWork(i) // 啟動(dòng)一個(gè)goroutine做工作
	}
	//主goroutine調(diào)用wg.Wait(),直到所有啟動(dòng)的goroutines都通過調(diào)用wg.Done()通知它們已經(jīng)完成工作
	wg.Wait() // 阻塞,直到WaitGroup的計(jì)數(shù)器為0
	fmt.Println("所有業(yè)務(wù)處理完成~~~")
}

使用 Mutex 和 Conditional Variables 實(shí)現(xiàn)阻塞

Mutex(互斥鎖)和條件變量可以用來同步訪問共享資源,并實(shí)現(xiàn)基于條件的阻塞。 

package main

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

func main() {
	var mtx sync.Mutex         //創(chuàng)建互斥鎖
	cond := sync.NewCond(&mtx) //使用mtx作為底層互斥鎖
	ready := false

	// 啟動(dòng)一個(gè) goroutine 來改變條件變量 ready 的值,并通知 cond。
	go func() {
		fmt.Println("循環(huán)跟goroutine是go內(nèi)部決定先調(diào)度的--------------------goroutine--------------------")
		time.Sleep(3 * time.Second)
		mtx.Lock() //使用互斥鎖
		ready = true
		cond.Signal() // 喚醒至少一個(gè)等待的 goroutine
		mtx.Unlock()  //解鎖
	}()

	mtx.Lock() // 鎖定互斥鎖,準(zhǔn)備進(jìn)入條件等待
	for !ready {
		fmt.Println("循環(huán)跟goroutine是go內(nèi)部決定先調(diào)度的--------------------阻塞--------------------")
		cond.Wait() // 阻塞,直到 cond.Signal() 被調(diào)用
		//mtx.Unlock()
	}
	mtx.Unlock() // 解鎖互斥鎖,繼續(xù)執(zhí)行(此處mtx.Unlock()在for循環(huán)里面阻塞等待完成后也可以,也可以沒有,因?yàn)橹骶€程會(huì)結(jié)束,但如果后續(xù)還需要獲取互斥鎖則必須要釋放否則報(bào)錯(cuò))

	fmt.Println("準(zhǔn)備繼續(xù)~~~")
}

這里是一些關(guān)鍵的修改和注意事項(xiàng):

  • sync.Cond 的使用需要一個(gè) sync.Mutex 作為其底層的互斥鎖。在使用 cond.Wait() 之前,必須先鎖定這個(gè)互斥鎖。

  • 在 cond.Wait() 調(diào)用中,當(dāng)前的互斥鎖會(huì)被自動(dòng)釋放,goroutine 會(huì)阻塞直到它被 cond.Signal() 或 cond.Broadcast() 喚醒。

  • 一旦 cond.Wait() 返回,goroutine 會(huì)重新獲取互斥鎖,然后繼續(xù)執(zhí)行循環(huán)或代碼塊。

  • 在 cond.Signal() 調(diào)用之后,您需要在某個(gè)地方調(diào)用 mtx.Unlock() 來釋放互斥鎖,否則主 goroutine 會(huì)在 cond.Wait() 之后無法獲取到鎖。

  • 您的代碼中,cond.Wait() 之后的 mtx.Unlock() 應(yīng)該在 for 循環(huán)之外,以避免在循環(huán)的每次迭代中重復(fù)加鎖和解鎖。 

在Go語言中,sync.Mutex(互斥鎖)用于保護(hù)共享資源不被多個(gè)goroutine同時(shí)修改,以避免競(jìng)態(tài)條件。sync.Cond(條件變量)與互斥鎖結(jié)合使用,可以在多個(gè)goroutine之間同步共享?xiàng)l件。以下是關(guān)于何時(shí)使用 mtx.Lock() 和 mtx.Unlock() 的指導(dǎo):

mtx.Lock()

  • 在訪問或修改由互斥鎖保護(hù)的共享資源之前使用。
  • 在調(diào)用 cond.Wait() 之前使用,以確保在等待條件變量時(shí),共享資源不會(huì)被其他goroutine并發(fā)訪問。
  • 在調(diào)用 cond.Signal() 或 cond.Broadcast() 之前使用,因?yàn)檫@些操作需要在互斥鎖保護(hù)的臨界區(qū)內(nèi)執(zhí)行。

mtx.Unlock()

  • 在完成對(duì)共享資源的訪問或修改后使用。
  • 在 cond.Wait() 返回后使用,因?yàn)槲覀円呀?jīng)完成了等待期間需要的共享資源訪問,并且需要重新獲取互斥鎖以繼續(xù)執(zhí)行。
  • 在不再需要互斥鎖保護(hù)當(dāng)前goroutine的執(zhí)行路徑時(shí)使用,以允許其他等待互斥鎖的goroutine繼續(xù)執(zhí)行。

注意事項(xiàng)

  • 互斥鎖必須在獲取后及時(shí)釋放,否則會(huì)導(dǎo)致死鎖。
  • 通常,獲取互斥鎖和釋放互斥鎖成對(duì)出現(xiàn),以避免忘記釋放鎖。

永久阻塞

Go 的運(yùn)行時(shí)的當(dāng)前設(shè)計(jì),假定程序員自己負(fù)責(zé)檢測(cè)何時(shí)終止一個(gè) goroutine 以及何時(shí)終止該程序。可以通過調(diào)用 os.Exit 或從 main() 函數(shù)的返回來以正常方式終止程序。而有時(shí)候我們需要的是使程序阻塞在這一行。

使用 sync.WaitGroup 

一直等待直到 WaitGroup 等于 0 

package main

import "sync"

func main() {
	var wg sync.WaitGroup
	wg.Add(1)
	wg.Wait()
}

空 select

 select{}是一個(gè)沒有任何 case 的 select,它會(huì)一直阻塞

package main

func main() {
	select{}
}

 死循環(huán)

雖然能阻塞,但會(huì) 100%占用一個(gè) cpu。不建議使用

package main

func main() {
	for {}
}

 用 sync.Mutex

一個(gè)已經(jīng)鎖了的鎖,再鎖一次會(huì)一直阻塞,這個(gè)不建議使用

package main

import "sync"

func main() {
	var m sync.Mutex
	m.Lock()
}

 os.Signal

系統(tǒng)信號(hào)量,在 go 里面也是個(gè) channel,在收到特定的消息之前一直阻塞  

package main

import (
	"os"
	"os/signal"
	"syscall"
)

func main() {
	sig := make(chan os.Signal, 2)
	//syscall.SIGTERM 是默認(rèn)的終止進(jìn)程信號(hào),通常由服務(wù)管理器(如systemd、supervisor等)發(fā)送來請(qǐng)求程序正常終止。
	//syscall.SIGINT 是中斷信號(hào),一般由用戶按下Ctrl+C鍵觸發(fā),用于請(qǐng)求程序中斷執(zhí)行
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
	<-sig
}

從終端發(fā)送信號(hào)

  • Ctrl+C: 在大多數(shù)Unix-like系統(tǒng)(包括Linux和macOS)以及Windows的命令行中,按 Ctrl+C 鍵會(huì)向當(dāng)前前臺(tái)進(jìn)程發(fā)送一個(gè) SIGINT(中斷)信號(hào)。這通常是停止Go程序的快捷方式。

  • Kill命令: 如果你的程序在后臺(tái)運(yùn)行,并且你知道其進(jìn)程ID(PID),可以通過終端發(fā)送一個(gè)信號(hào)。例如,發(fā)送一個(gè) SIGTERM 信號(hào),可以使用:kill PID或者指定型號(hào)類型kill -SIGTERM PID

 從Go代碼內(nèi)部發(fā)送信號(hào)

package main

import (
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	sig := make(chan os.Signal, 2)
	//syscall.SIGTERM 是默認(rèn)的終止進(jìn)程信號(hào),通常由服務(wù)管理器(如systemd、supervisor等)發(fā)送來請(qǐng)求程序正常終止。
	//syscall.SIGINT 是中斷信號(hào),一般由用戶按下Ctrl+C鍵觸發(fā),用于請(qǐng)求程序中斷執(zhí)行
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)

	go func() {
		time.Sleep(10 * time.Second)
		sig <- syscall.SIGTERM
	}()

	go func() {
		time.Sleep(5 * time.Second)
		sig <- syscall.SIGINT
	}()

	<-sig
}

使用外部工具或服務(wù)管理器

如果你的Go程序作為服務(wù)運(yùn)行,可能由如systemd、supervisord等服務(wù)管理器控制,這些管理器通常提供了發(fā)送信號(hào)給托管服務(wù)的機(jī)制。具體操作需參考相應(yīng)服務(wù)管理器的文檔。

空 channel 或者 nil channel 

channel 會(huì)一直阻塞直到收到消息,nil channel 永遠(yuǎn)阻塞。 

package main

func main() {
	c := make(chan struct{})
	<-c
}
package main

func main() {
	var c chan struct{} //nil channel
	<-c
}

 總結(jié)

 注意上面寫的的代碼大部分不能直接運(yùn)行,都會(huì) panic,提示“all goroutines are asleep - deadlock!”,因?yàn)?go 的 runtime 會(huì)檢查你所有的 goroutine 都卡住了, 沒有一個(gè)要執(zhí)行。

你可以在阻塞代碼前面加上一個(gè)或多個(gè)你自己業(yè)務(wù)邏輯的 goroutine,這樣就不會(huì) deadlock 了。

到此這篇關(guān)于Go 阻塞的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Go 阻塞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法

    Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法

    這篇文章主要介紹了Go語言使用HTTP包創(chuàng)建WEB服務(wù)器的方法,結(jié)合實(shí)例形式分析了Go語言基于HTTP包創(chuàng)建WEB服務(wù)器客戶端與服務(wù)器端的實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2016-07-07
  • Golang使用Gin實(shí)現(xiàn)文件上傳的示例代碼

    Golang使用Gin實(shí)現(xiàn)文件上傳的示例代碼

    本文我們主要介紹了Golang如何使用Gin實(shí)現(xiàn)文件上傳,Go標(biāo)準(zhǔn)庫(kù)net/http對(duì)文件上傳已經(jīng)提供了非常完善的支持,而Gin框架在其基礎(chǔ)上進(jìn)一步封裝,因此使用Gin開發(fā)文件上傳功能時(shí),只需要簡(jiǎn)單幾行代碼便可以實(shí)現(xiàn),需要的朋友可以參考下
    2024-02-02
  • Golang應(yīng)用執(zhí)行Shell命令實(shí)戰(zhàn)

    Golang應(yīng)用執(zhí)行Shell命令實(shí)戰(zhàn)

    本文主要介紹了Golang應(yīng)用執(zhí)行Shell命令實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Golang中的深拷貝與淺拷貝使用

    Golang中的深拷貝與淺拷貝使用

    本文主要介紹了Golang中的深拷貝與淺拷貝使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 關(guān)于Go語言中的IO操作詳解

    關(guān)于Go語言中的IO操作詳解

    在現(xiàn)代軟件開發(fā)中,高效的輸入輸出(I/O)操作是提高程序性能的關(guān)鍵之一,Go語言提供了豐富的I/O操作接口,使得文件讀寫、網(wǎng)絡(luò)通信等任務(wù)變得簡(jiǎn)單而高效,本文介紹了關(guān)于Go語言中的IO操作,需要的朋友可以參考下
    2024-10-10
  • 一文帶你了解Go語言標(biāo)準(zhǔn)庫(kù)math和rand的常用函數(shù)

    一文帶你了解Go語言標(biāo)準(zhǔn)庫(kù)math和rand的常用函數(shù)

    這篇文章主要為大家詳細(xì)介紹了Go語言標(biāo)準(zhǔn)庫(kù)math和rand中的常用函數(shù),文中的示例代碼講解詳細(xì), 對(duì)我們學(xué)習(xí)Go語言有一定的幫助,感興趣的小伙伴可以了解一下
    2022-12-12
  • Go在GoLand中引用github.com中的第三方包具體步驟

    Go在GoLand中引用github.com中的第三方包具體步驟

    這篇文章主要給大家介紹了關(guān)于Go在GoLand中引用github.com中第三方包的具體步驟,文中通過圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Go具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-01-01
  • Golang交叉編譯之跨平臺(tái)編譯使用詳解

    Golang交叉編譯之跨平臺(tái)編譯使用詳解

    這篇文章主要為大家介紹了Golang交叉編譯之跨平臺(tái)編譯使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • Golang常用的幾種密碼加密方式分享

    Golang常用的幾種密碼加密方式分享

    這篇文章給大家介紹了Golang常用的幾種密碼加密方式,加密有兩種方式,一種是直接加密,一種是鹽值加密,直接加密指的是將原始密碼直接進(jìn)行加密,鹽值加密則是在進(jìn)行密碼加密之前,文中有詳細(xì)的代碼示例,需要的朋友可以參考下
    2023-08-08
  • Go語言七篇入門教程三函數(shù)方法及接口

    Go語言七篇入門教程三函數(shù)方法及接口

    這篇文章主要為大家介紹了Go語言的函數(shù)方法及接口的示例詳解,本文是Go語言七篇入門系列文章,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-11-11

最新評(píng)論