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

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

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

阻塞 

在Go語言中,阻塞通常指的是一個(gè)goroutine(輕量級線程)在等待另一個(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)樗粫?dǎo)致計(jì)數(shù)變?yōu)樨?fù)數(shù)(如果已經(jīng)到達(dá)零,則會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) // 啟動一個(gè)goroutine做工作
	}
	//主goroutine調(diào)用wg.Wait(),直到所有啟動的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

	// 啟動一個(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)橹骶€程會結(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)前的互斥鎖會被自動釋放,goroutine 會阻塞直到它被 cond.Signal() 或 cond.Broadcast() 喚醒。

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

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

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

在Go語言中,sync.Mutex(互斥鎖)用于保護(hù)共享資源不被多個(gè)goroutine同時(shí)修改,以避免競態(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í),共享資源不會被其他goroutine并發(fā)訪問。
  • 在調(diào)用 cond.Signal() 或 cond.Broadcast() 之前使用,因?yàn)檫@些操作需要在互斥鎖保護(hù)的臨界區(qū)內(nèi)執(zhí)行。

mtx.Unlock()

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

注意事項(xiàng)

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

永久阻塞

Go 的運(yùn)行時(shí)的當(dāng)前設(shè)計(jì),假定程序員自己負(fù)責(zé)檢測何時(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,它會一直阻塞

package main

func main() {
	select{}
}

 死循環(huán)

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

package main

func main() {
	for {}
}

 用 sync.Mutex

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

package main

import "sync"

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

 os.Signal

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

package main

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

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

從終端發(fā)送信號

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

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

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

package main

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

func main() {
	sig := make(chan os.Signal, 2)
	//syscall.SIGTERM 是默認(rèn)的終止進(jìn)程信號,通常由服務(wù)管理器(如systemd、supervisor等)發(fā)送來請求程序正常終止。
	//syscall.SIGINT 是中斷信號,一般由用戶按下Ctrl+C鍵觸發(fā),用于請求程序中斷執(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ā)送信號給托管服務(wù)的機(jī)制。具體操作需參考相應(yīng)服務(wù)管理器的文檔。

空 channel 或者 nil channel 

channel 會一直阻塞直到收到消息,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)行,都會 panic,提示“all goroutines are asleep - deadlock!”,因?yàn)?go 的 runtime 會檢查你所有的 goroutine 都卡住了, 沒有一個(gè)要執(zhí)行。

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

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

相關(guān)文章

  • Go語言切片擴(kuò)容原理和過程

    Go語言切片擴(kuò)容原理和過程

    切片(Slice)在 Go 語言中,有一個(gè)很常用的數(shù)據(jù)結(jié)構(gòu),切片是一個(gè)擁有相同類型元素的可變長度的序列,它是基于數(shù)組類型做的一層封裝,它非常靈活,支持自動擴(kuò)容,并發(fā)不安全,本文給大家介紹了Go 語言切片如何擴(kuò)容,需要的朋友可以參考下
    2025-02-02
  • Golang中使用Swagger生成API文檔的流程步驟

    Golang中使用Swagger生成API文檔的流程步驟

    Swagger 是一款強(qiáng)大的 API 文檔生成工具,可以幫助開發(fā)者輕松創(chuàng)建、管理和展示 RESTful API 文檔,在本文中,我們將介紹如何在 Golang 項(xiàng)目中使用 Swagger 來生成 API 文檔,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-07-07
  • go實(shí)現(xiàn)fping功能

    go實(shí)現(xiàn)fping功能

    這篇文章主要介紹了go實(shí)現(xiàn)fping功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • golang interface判斷為空nil的實(shí)現(xiàn)代碼

    golang interface判斷為空nil的實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang interface判斷為空nil的實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • golang守護(hù)進(jìn)程用法示例

    golang守護(hù)進(jìn)程用法示例

    這篇文章主要介紹了golang守護(hù)進(jìn)程用法,結(jié)合實(shí)例形式分析了Go語言守護(hù)進(jìn)程的具體實(shí)現(xiàn)與使用技巧,需要的朋友可以參考下
    2016-07-07
  • 在Golang中使用http.FileServer返回靜態(tài)文件的操作

    在Golang中使用http.FileServer返回靜態(tài)文件的操作

    這篇文章主要介紹了在Golang中使用http.FileServer返回靜態(tài)文件的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Golang?throttled基于GCRA速率限制庫使用探索

    Golang?throttled基于GCRA速率限制庫使用探索

    這篇文章主要為大家介紹了Golang?throttled基于GCRA速率限制庫使用實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • golang操作mongodb的方法

    golang操作mongodb的方法

    這篇文章主要介紹了golang操作mongodb的方法,涉及Go語言操作mongodb的連接、讀取及顯示的方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • 利用Go Plugin實(shí)現(xiàn)插件化編程的簡單方法

    利用Go Plugin實(shí)現(xiàn)插件化編程的簡單方法

    Golang官方提供了plugin模塊,該模塊可以支持插件開,下面這篇文章主要給大家介紹了關(guān)于如何利用Go Plugin實(shí)現(xiàn)插件化編程的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Golang 空map和未初始化map的注意事項(xiàng)說明

    Golang 空map和未初始化map的注意事項(xiàng)說明

    這篇文章主要介紹了Golang 空map和未初始化map的注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論

屯门区| 磐安县| 孝昌县| 平和县| 神农架林区| 西贡区| 延寿县| 文登市| 蒙城县| 阿拉善盟| 沁源县| 屏边| 绿春县| 佛坪县| 自贡市| 阳原县| 瓮安县| 鸡东县| 商洛市| 开江县| 杨浦区| 马龙县| 右玉县| 湖南省| 邵东县| 西乡县| 大宁县| 樟树市| 安塞县| 微博| 吉首市| 绵阳市| 藁城市| 鹤岗市| 信丰县| 鹤壁市| 岳池县| 彭山县| 贵港市| 东莞市| 青神县|