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

Go并發(fā)4種方法簡(jiǎn)明講解

 更新時(shí)間:2022年04月06日 16:35:39   投稿:wdc  
這篇文章主要介紹了Go并發(fā)4種方法簡(jiǎn)明講解,需要的朋友可以參考下

一、goroutine

1、協(xié)程(Coroutine)

Golang 在語(yǔ)言層面對(duì)并發(fā)編程進(jìn)行了支持,使用了一種協(xié)程(goroutine)機(jī)制,

協(xié)程本質(zhì)上是一種用戶態(tài)線程,不需要操作系統(tǒng)來(lái)進(jìn)行搶占式調(diào)度,但是又寄生于線程中,因此系統(tǒng)開(kāi)銷極小,可以有效的提高線程的任務(wù)并發(fā)性,而避免多線程的缺點(diǎn)。但是協(xié)程需要語(yǔ)言上的支持,需要用戶自己實(shí)現(xiàn)調(diào)度器,因?yàn)樵贕o語(yǔ)言中,實(shí)現(xiàn)了調(diào)度器所以我們可以很方便的能過(guò) go關(guān)鍵字來(lái)使用協(xié)程。

func main() {
	for i := 0; i <10; i++ {
		go func(i int) {
			for  {
				fmt.Printf("Hello goroutine %d\n",i)
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
}

最簡(jiǎn)單的一個(gè)并發(fā)編程小例子,并發(fā)輸出一段話。

我們同時(shí)開(kāi)了10個(gè)協(xié)程進(jìn)行輸出,每次在fmt.printf時(shí)交出控制權(quán)(不一定每次都會(huì)交出控制權(quán)),回到調(diào)度器中,再由調(diào)度器分配。

2、goroutine 可能切換的點(diǎn)

  • I/O,Select
  • channel
  • 等待鎖
  • 函數(shù)調(diào)用
  • runtime.Gosched()

我們看一個(gè)小例子:

func main() {
	var a [10]int
	for i := 0; i <10; i++ {
		go func(i int) {
			for  {
				a[i]++
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
	fmt.Println(a)
}

在這里,代碼直接鎖死,程序沒(méi)有退出,因?yàn)樵趫?zhí)行函數(shù)中沒(méi)有協(xié)程的切換,因?yàn)?nbsp;main函數(shù)也是一個(gè)協(xié)程。

如果想要程序退出,可以通過(guò) runtime.Gosched()函數(shù),在執(zhí)行函數(shù)中添加一行。

for  {
  a[i]++
  runtime.Gosched()
}

加上這個(gè)函數(shù)之后,代碼是可以正常執(zhí)行了,但是真的是正常執(zhí)行嗎?不一定,我們可以使用 -reac命令來(lái)看一下數(shù)據(jù)是否有沖突:

這說(shuō)明數(shù)據(jù)還是有沖突的,數(shù)組a中的元素一邊在做自增,一邊在輸出。解決這個(gè)問(wèn)題,我們只能使用 channel 來(lái)解決。

二、Channel

Channel 中 Go語(yǔ)言在語(yǔ)言級(jí)別提供了對(duì) goroutine 之間通信的支持,我們可以使用 channel 在兩個(gè)或者多個(gè)goroutine之間進(jìn)行信息傳遞,能過(guò) channel 傳遞對(duì)像的過(guò)程和調(diào)用函數(shù)時(shí)的參數(shù)傳遞行為一樣,可以傳遞普通參數(shù)和指針。

Channel 有兩種模式:

var ch1 = make(chan int)		// 無(wú)緩沖 channel,同步
var ch2 = make(chan int, 2)	// 有緩沖 channel, 異步

無(wú)緩沖的方式,數(shù)據(jù)進(jìn)入 channel 只要沒(méi)有被接收,就會(huì)處在阻塞狀態(tài)。

var ch1 = make(chan int)		// 無(wú)緩沖 channel,同步
ch1 <- 1
ch1 <- 2
//  error: all goroutines are asleep - deadlock!
fmt.Println(<-ch1)

如果想要運(yùn)行,必須要再開(kāi)一個(gè)協(xié)程不停的去請(qǐng)求數(shù)據(jù):

var ch1 = make(chan int)		// 無(wú)緩沖 channel,同步
go func() {
  for  {
    n := <-ch1
    fmt.Println(n)
  }
}()
ch1 <- 1
ch1 <- 2

有緩沖的方式,只要緩沖區(qū)沒(méi)有滿就可以一直進(jìn)數(shù)據(jù),緩沖區(qū)在填滿之后沒(méi)有接收也會(huì)處理阻塞狀態(tài)。

func bufferChannel() {
	var ch2 = make(chan int,2)
	ch2<-1
	ch2<-2
	fmt.Println(ch2)
  // 不加這一行的話,是可以正常運(yùn)行的
	ch2<-3			// error: all goroutines are asleep - deadlock!
}

1、chaanel 指定方向

比如我現(xiàn)在有一個(gè)函數(shù)創(chuàng)建一個(gè) channel,并且不斷的需要消費(fèi)channel中的數(shù)據(jù):

func worker(ch chan int) {
	for {
		fmt.Printf("hello goroutine worker %d\n", <-ch)
	}
}

func createWorker() chan int{
	ch := make(chan int)
	go worker(ch)
	return ch
}

func main() {
	ch := createWorker()
	ch<-1
	ch<-2
	ch<-3
	time.Sleep(time.Millisecond)
}

這個(gè)函數(shù)我是要給別人用的,但是我怎么保證使用 createWorker 函數(shù)創(chuàng)建的 channel 都是往里面?zhèn)魅霐?shù)據(jù)的呢?

如果外面有人消費(fèi)了這個(gè) channel 中的數(shù)據(jù),我們?cè)趺聪拗疲?/p>

這個(gè)時(shí)候,我們就可以給返回的channel 加上方向,指明這個(gè) channel 中能往里傳入數(shù)據(jù),不能從中取數(shù)據(jù):

func worker(ch <-chan int) {
	for {
		fmt.Printf("hello goroutine worker %d\n", <-ch)
	}
}

func createWorker() chan<- int{
	ch := make(chan int)
	go worker(ch)
	return ch
}

我們可以在返回 channel 的地方加上方向,指明返回的函數(shù)只能是一個(gè)往里傳入數(shù)據(jù),不能從中取數(shù)據(jù)。

并且我們還可以給專門消費(fèi)的函數(shù)加上一個(gè)方向,指明這個(gè)函數(shù)只能出不能進(jìn)。

2、channel 關(guān)閉

在使用 channel 的時(shí)候,隨說(shuō)我們可以等待channel中的函數(shù)使用完之后自己結(jié)束,或者等待 main 函數(shù)結(jié)束時(shí)關(guān)閉所有的 goroutine 函數(shù),但是這樣的方式顯示不夠優(yōu)雅。

當(dāng)一個(gè)數(shù)據(jù)我們明確知道他的結(jié)束時(shí)候,我們可以發(fā)送一個(gè)關(guān)閉信息給這個(gè) channel ,當(dāng)這個(gè) channel 接收到這個(gè)信號(hào)之后,自己關(guān)閉。

// 方法一
func worker(ch <-chan int) {
	for {
		if c ,ok := <- ch;ok{
			fmt.Printf("hello goroutine worker %d\n", c)
		}else {
			break
		}
	}
}
// 方法二
func worker(ch <-chan int) {
	for c := range ch{
		fmt.Printf("hello goroutine worker %d\n", c)
	}
}

func main() {
	ch := createWorker()
	ch<-1
	ch<-2
	ch<-3
	close(ch)
	time.Sleep(time.Millisecond)
}

通過(guò) Closeb函數(shù),我們可以能過(guò) channel 已經(jīng)關(guān)閉,并且我們還可以通過(guò)兩種方法判斷通道內(nèi)是否還有值。

三、Select

當(dāng)我們?cè)趯?shí)際開(kāi)發(fā)中,我們一般同時(shí)處理兩個(gè)或者多個(gè) channel 的數(shù)據(jù),我們想要完成一個(gè)那個(gè) channel 先來(lái)數(shù)據(jù),我們先來(lái)處理個(gè)那 channel 怎么辦呢?

此時(shí),我們就可以使用 select 調(diào)度:

func genInt() chan int {
	ch := make(chan int)
	go func() {
		i := 0
		for {
			// 隨機(jī)兩秒以內(nèi)生成一次數(shù)據(jù)
			time.Sleep(time.Duration(rand.Intn(2000)) * time.Millisecond)
			ch <- i
			i++
		}
	}()
	return ch
}

func main() {
	var c1 = genInt()
	var c2 = genInt()
	for {
		select {
		case n := <-c1:
			fmt.Printf("server 1 generator %d\n", n)
		case n := <- c2:
			fmt.Printf("server 2 generator %d\n", n)
		}
	}
}

1、定時(shí)器

	for {
		tick := time.Tick(time.Second)
		select {
		case n := <-c1:
			fmt.Printf("server 1 generator %d\n", n)
		case n := <-c2:
			fmt.Printf("server 2 generator %d\n", n)
		case <-tick:
			fmt.Println("定時(shí)每秒輸出一次!")
		}
	}

2、超時(shí)

	for {
		tick := time.Tick(time.Second)
		select {
		case n := <-c1:
			fmt.Printf("server 1 generator %d\n", n)
		case n := <-c2:
			fmt.Printf("server 2 generator %d\n", n)
		case <-tick:
			fmt.Println("定時(shí)每秒輸出一次!")
		case <-time.After(1300 * time.Millisecond): // 如果 1.3秒內(nèi)沒(méi)有數(shù)據(jù)進(jìn)來(lái),那么就輸出超時(shí)
			fmt.Println("timeout")
		}
	}

四、傳統(tǒng)的并發(fā)控制

1、sync.Mutex

type atomicInt struct {
	value int
	lock sync.Mutex
}

func (a *atomicInt) increment() {
	a.lock.Lock()
	defer a.lock.Unlock()		// 使用 defer 解鎖,以防忘記
	a.value++
}

func main() {
	var a atomicInt
	a.increment()
	go func() {
		a.increment()
	}()
	time.Sleep(time.Millisecond)
	fmt.Println(a.value)
}

2、sync.WaitGroup

type waitGrouInt struct {
	value int
	wg sync.WaitGroup
}

func (w *waitGrouInt) addInt() {
	w.wg.Add(1)
	w.value++
}

func main() {
	var w waitGrouInt
	for i := 0; i < 10; i++ {
		w.addInt()
		w.wg.Done()
	}
	w.wg.Wait()
	fmt.Println(w.value)
}

 更多關(guān)于Go并發(fā)簡(jiǎn)明講解請(qǐng)查看下面的相關(guān)鏈接

相關(guān)文章

  • Golang Defer基礎(chǔ)操作詳解

    Golang Defer基礎(chǔ)操作詳解

    在golang當(dāng)中,defer代碼塊會(huì)在函數(shù)調(diào)用鏈表中增加一個(gè)函數(shù)調(diào)用。這個(gè)函數(shù)調(diào)用不是普通的函數(shù)調(diào)用,而是會(huì)在函數(shù)正常返回,也就是return之后添加一個(gè)函數(shù)調(diào)用。因此,defer通常用來(lái)釋放函數(shù)內(nèi)部變量
    2022-10-10
  • golang實(shí)現(xiàn)并發(fā)控制的方法和技巧

    golang實(shí)現(xiàn)并發(fā)控制的方法和技巧

    golang 是一門支持并發(fā)的編程語(yǔ)言,它提供了 goroutine 和 channel 等強(qiáng)大的特性,讓我們可以輕松地創(chuàng)建和管理多個(gè)執(zhí)行單元,實(shí)現(xiàn)高效的任務(wù)處理,在本文中,我們將介紹一些 golang 的并發(fā)控制的方法和技巧,希望對(duì)你有所幫助
    2024-03-03
  • Go語(yǔ)言中的基礎(chǔ)數(shù)據(jù)類型使用實(shí)例

    Go語(yǔ)言中的基礎(chǔ)數(shù)據(jù)類型使用實(shí)例

    這篇文章主要為大家介紹了Go中的基礎(chǔ)數(shù)據(jù)類型使用示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • golang敏感詞過(guò)濾的實(shí)現(xiàn)

    golang敏感詞過(guò)濾的實(shí)現(xiàn)

    本文主要介紹了golang敏感詞過(guò)濾的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Golang 高效排序數(shù)據(jù)詳情

    Golang 高效排序數(shù)據(jù)詳情

    本文我們介紹了怎么使用 Golang 語(yǔ)言標(biāo)準(zhǔn)庫(kù) sort 包排序數(shù)據(jù),需要注意的是,除了本文使用的類型之外,其它任意類型只要實(shí)現(xiàn) sort.Interface 的三個(gè)方法,都可以調(diào)用 sort.Sort() 函數(shù)排序數(shù)據(jù)。
    2021-11-11
  • Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單網(wǎng)絡(luò)端口掃描方法

    Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單網(wǎng)絡(luò)端口掃描方法

    這篇文章主要介紹了Go語(yǔ)言實(shí)現(xiàn)的簡(jiǎn)單網(wǎng)絡(luò)端口掃描方法,實(shí)例分析了Go語(yǔ)言網(wǎng)絡(luò)程序的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Golang實(shí)現(xiàn)解析JSON的三種方法總結(jié)

    Golang實(shí)現(xiàn)解析JSON的三種方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)解析JSON的三種方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)了解JSON有一定幫助,需要的可以參考一下
    2022-09-09
  • GoLang?socket網(wǎng)絡(luò)編程傳輸數(shù)據(jù)包時(shí)進(jìn)行長(zhǎng)度校驗(yàn)的方法

    GoLang?socket網(wǎng)絡(luò)編程傳輸數(shù)據(jù)包時(shí)進(jìn)行長(zhǎng)度校驗(yàn)的方法

    在GoLang?socket網(wǎng)絡(luò)編程中,為了確保數(shù)據(jù)交互的穩(wěn)定性和安全性,通常會(huì)通過(guò)傳輸數(shù)據(jù)的長(zhǎng)度進(jìn)行校驗(yàn),發(fā)送端首先發(fā)送數(shù)據(jù)長(zhǎng)度,然后發(fā)送數(shù)據(jù)本體,接收端則根據(jù)接收到的數(shù)據(jù)長(zhǎng)度和數(shù)據(jù)本體進(jìn)行比較,以此來(lái)確認(rèn)數(shù)據(jù)是否傳輸成功
    2024-11-11
  • go語(yǔ)言中數(shù)據(jù)接口set集合的實(shí)現(xiàn)

    go語(yǔ)言中數(shù)據(jù)接口set集合的實(shí)現(xiàn)

    set集合是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),它代表了一個(gè)唯一元素的集合,本文主要介紹了set的基本特性,包括唯一性、無(wú)序性、可變性和集合運(yùn)算,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • Go內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧

    Go內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言內(nèi)存分配之結(jié)構(gòu)體優(yōu)化技巧的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11

最新評(píng)論

武乡县| 溆浦县| 乃东县| 藁城市| 红河县| 韩城市| 喀喇| 庆安县| 秦安县| 全椒县| 青州市| 古浪县| 锡林浩特市| 昆山市| 楚雄市| 潮州市| 巫山县| 铁力市| 五指山市| 江孜县| 略阳县| 泉州市| 康马县| 广德县| 阳江市| 曲阳县| 西乌珠穆沁旗| 宣威市| 晋宁县| 南昌县| 高尔夫| 小金县| 繁昌县| 九寨沟县| 德州市| 扎兰屯市| 敦煌市| 霞浦县| 永寿县| 泰州市| 鄂温|