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

關于golang高并發(fā)的實現(xiàn)與注意事項說明

 更新時間:2021年05月08日 11:06:17   作者:HandsomeBoy@Guess  
這篇文章主要介紹了關于golang高并發(fā)的實現(xiàn)與注意事項說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

一、并發(fā)的意義

并發(fā)的意義就是讓 一個程序同時做多件事情,其目的只是為了能讓程序同時做另一件事情而已,而不是為了讓程序運行的更快(如果是多核處理器,而且任務可以分成相互獨立的部分,那么并發(fā)確實可以讓事情解決的更快)。

golang從語言級別上對并發(fā)提供了支持,而且在啟動并發(fā)的方式上直接添加了語言級的關鍵字,不必非要按照固定的格式來定義線程函數,也不必因為啟動線程的時候只能給線程函數傳遞一個參數而煩惱。

二、并發(fā)的啟動

go的并發(fā)啟動非常簡單,幾乎沒有什么額外的準備工作,要并發(fā)的函數和一般的函數沒有什么區(qū)別,參數隨意,啟動的時候只需要加一個go關鍵之即可,其最精髓的部分在于這些協(xié)程(協(xié)程類似于線程,但是是更輕量的線程)的調度。

package main
 
import (
 "fmt"
 "time"
)
 
func comFunc() {
 fmt.Println("This is a common function.")
}
 
func main() {
 go comFunc()
 time.Sleep(time.Second * 3)
}

三、協(xié)程間的同步與通信

1、sync.WaitGroup

sync包中的WaitGroup實現(xiàn)了一個類似任務隊列的結構,你可以向隊列中加入任務,任務完成后就把任務從隊列中移除,如果隊列中的任務沒有全部完成,隊列就會觸發(fā)阻塞以阻止程序繼續(xù)運行,具體用法參考如下代碼:

package main
import (
 "fmt"
 "sync"
)
var waitGroup sync.WaitGroup
func Afunction(index int) {
 fmt.Println(index)
 waitGroup.Done() //任務完成,將任務隊列中的任務數量-1,其實.Done就是.Add(-1)
}
 
func main() {
 for i := 0; i < 10; i++ {
  waitGroup.Add(1) //每創(chuàng)建一個goroutine,就把任務隊列中任務的數量+1
  go Afunction(i)
 }
 waitGroup.Wait() //.Wait()這里會發(fā)生阻塞,直到隊列中所有的任務結束就會解除阻塞
}

2、channel

channel是一種golang內置的類型,英語的直譯為"通道",其實,它真的就是一根管道,而且是一個先進先出的數據結構。

我們能對channel進行的操作只有4種:

(1) 創(chuàng)建chennel (通過make()函數)

(2) 放入數據 (通過 channel <- data 操作)

(3) 取出數據 (通過 <-channel 操作)

(4) 關閉channel (通過close()函數)

channel的3種性質入如下:

(1) channel是一種自動阻塞的管道。

如果管道滿了,一個對channel放入數據的操作就會阻塞,直到有某個routine從channel中取出數據,這個放入數據的操作才會執(zhí)行。相反同理,如果管道是空的,一個從channel取出數據的操作就會阻塞,直到某個routine向這個channel中放入數據,這個取出數據的操作才會執(zhí)行。這是channel最重要的一個性質?。?!

package main
func main() {
 ch := make(chan int, 3)
 ch <- 1
 ch <- 1
 ch <- 1
 ch <- 1 //這一行操作就會發(fā)生阻塞,因為前三行的放入數據的操作已經把channel填滿了
}
package main
func main() {
 ch := make(chan int, 3)
 <-ch //這一行會發(fā)生阻塞,因為channel才剛創(chuàng)建,是空的,沒有東西可以取出
}

(2)channel分為有緩沖的channel和無緩沖的channel。

兩種channel的創(chuàng)建方法如下:

ch := make(chan int)  //無緩沖的channel,同等于make(chan int, 0)
ch := make(chan int, 5) //一個緩沖區(qū)大小為5的channel

無緩沖通道與有緩沖通道的主要區(qū)別為:無緩沖通道存取數據是同步的,即如果通道中無數據,則通道一直處于阻塞狀態(tài);有緩沖通道存取數據是異步的,即存取數據互不干擾,只有當通道中已滿時,存數據操作,通道阻塞;當通道中為空時,取數據操作,通道阻塞。

因此,使用無緩沖的channel時,放入操作和取出操作不能在同一個routine中,而且應該是先確保有某個routine對它執(zhí)行取出操作,然后才能在另一個routine中執(zhí)行放入操作,否則會發(fā)生死鎖現(xiàn)象,示例如下:

package main 
import (
 "fmt"
 "sync"
)
 
var waitGroup sync.WaitGroup //使用wg等待所有routine執(zhí)行完畢,并輸出相應的提示信息
 
func AFunc(ch chan int) {
 waitGroup.Add(1)
FLAG:
 for {
  select {
  case val := <-ch:
   fmt.Println(val)
   break FLAG
  }
 }
 waitGroup.Done()
 fmt.Println("WaitGroup Done")
}
 
func main() {
 
 ch := make(chan int) //無緩沖通道
 execMode := 0        //執(zhí)行模式 0:先啟動并發(fā),正常輸出100 1:后啟動并發(fā),發(fā)生死鎖
 switch execMode {
 case 0:
  go AFunc(ch)
  ch <- 100
 case 1:
  ch <- 100
  go AFunc(ch)
 }
 waitGroup.Wait()
 close(ch)
}

使用帶緩沖的channel時,因為有緩沖空間,所以只要緩沖區(qū)不滿,放入操作就不會阻塞,同樣,只要緩沖區(qū)不空,取出操作就不會阻塞。

而且,帶有緩沖的channel的放入和取出操作可以用在同一個routine中。

但是,一定要注意放入和取出的速率問題,否則也會發(fā)生死鎖現(xiàn)象,示例如下:

package main
import (
 "fmt"
 "sync"
)
var waitGroup sync.WaitGroup
func AFunc(ch chan int, putMode int) {
 val := <-ch
 switch putMode {
 case 0:
  fmt.Printf("Vaule=%d\n", val)
 case 1:
  fmt.Printf("Vaule=%d\n", val)
  for i := 1; i <= 5; i++ {
   ch <- i * val
  }
 case 2:
  fmt.Printf("Vaule=%d\n", val)
  for i := 1; i <= 5; i++ {
   <-ch
  }
 }
 
 waitGroup.Done()
 fmt.Println("WaitGroup Done", val)
}
 
func main() {
 ch := make(chan int, 10)
 putMode := 0 //該模式下,能夠正常輸出所有數據
 //putMode := 1//當放入速度遠大于取數速度時,程序阻塞
 //putMode := 2//當取數速度遠大于放數速度時,程序阻塞
 for i := 0; i < 1000; i++ {
  ch <- i
  waitGroup.Add(1)
  go AFunc(ch, putMode)
 }
 waitGroup.Wait()
 close(ch)
}

(3)關閉后的channel可以取數據,但是不能放數據。

而且,channel在執(zhí)行了close()后并沒有真的關閉,channel中的數據全部取走之后才會真正關閉。

package main
func main() {
 ch := make(chan int, 5)
 ch <- 1
 ch <- 1
 close(ch)
 ch <- 1 //不能對關閉的channel執(zhí)行放入操作
        
        // 會觸發(fā)panic
}
package main
func main() {
 ch := make(chan int, 5)
 ch <- 1
 ch <- 1
 close(ch)
 <-ch //只要channel還有數據,就可能執(zhí)行取出操作
 
        //正常結束
}
package main 
import "fmt" 
func main() {
 ch := make(chan int, 5)
 ch <- 1
 ch <- 1
 ch <- 1
 ch <- 1
 close(ch)  //如果執(zhí)行了close()就立即關閉channel的話,下面的循環(huán)就不會有任何輸出了
 for {
  data, ok := <-ch
  if !ok {
   break
  }
  fmt.Println(data)
 }
 
 // 輸出:
 // 1
 // 1
 // 1
 // 1
 // 
 // 調用了close()后,只有channel為空時,channel才會真的關閉
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。

相關文章

  • Go-RESTful實現(xiàn)下載功能思路詳解

    Go-RESTful實現(xiàn)下載功能思路詳解

    這篇文章主要介紹了Go-RESTful實現(xiàn)下載功能,文件下載包括文件系統(tǒng)IO和網絡IO,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • 一文初探?Goroutine?與?channel基本用法

    一文初探?Goroutine?與?channel基本用法

    這篇文章主要為大家介紹了一文初探?Goroutine?與?channel基本用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • Golang在Mac、Linux、Windows下如何交叉編譯的實現(xiàn)

    Golang在Mac、Linux、Windows下如何交叉編譯的實現(xiàn)

    這篇文章主要介紹了Golang在Mac、Linux、Windows下如何交叉編譯的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • Golang使用第三方包viper讀取yaml配置信息操作

    Golang使用第三方包viper讀取yaml配置信息操作

    這篇文章主要介紹了Golang使用第三方包viper讀取yaml配置信息操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go語言中的template使用示例詳解

    go語言中的template使用示例詳解

    在Go語言中,可以通過text/template和html/template包來處理模板,本文提供了一個使用Go模板的基本示例,包括導入包、創(chuàng)建數據結構、定義模板、執(zhí)行模板及運行程序,通過這些步驟,可以輸出一個格式化的YAML配置
    2024-10-10
  • golang官方嵌入文件到可執(zhí)行程序的示例詳解

    golang官方嵌入文件到可執(zhí)行程序的示例詳解

    這篇文章主要介紹了golang官方嵌入文件到可執(zhí)行程序,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • goland服務熱重啟的配置文件

    goland服務熱重啟的配置文件

    這篇文章主要介紹了goland服務熱重啟的配置文件,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • Golang的鎖機制與使用技巧小結

    Golang的鎖機制與使用技巧小結

    本文主要介紹了Golang的鎖機制與使用技巧小結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 深入理解GO語言的面向對象

    深入理解GO語言的面向對象

    相信很多人當初開發(fā)go語言的時候就是因為C++的特性太過于繁雜,從而使得很多C++的開發(fā)者因為C++的特性而頭疼,go語言成功的精簡了C++的特性,使其很簡潔,很少的特性,卻可以完成很多的事情。下面我們就來詳細理解下GO語言的面向對象。
    2016-10-10
  • Golang動態(tài)數組的實現(xiàn)示例

    Golang動態(tài)數組的實現(xiàn)示例

    動態(tài)數組能自動調整大小,與靜態(tài)數組不同,其大小不固定,可根據需求變化,實現(xiàn)通常依賴于數據結構如鏈表或數組加額外信息,本文就來介紹一下Golang動態(tài)數組的實現(xiàn)示例,感興趣的可以了解一下
    2024-10-10

最新評論