亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

golang 限制同一時間的并發(fā)量操作

 更新時間:2020年12月14日 15:27:48   作者:小辣抓  
這篇文章主要介紹了golang 限制同一時間的并發(fā)量操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

go的并發(fā)量是很厲害的,goroutine創(chuàng)建的代價極小,其中一個重要的原因是因為go采用了分段棧技術(shù),每一個goroutine只占極小的空間。與此同時,goroutine是語言層面的,減少了內(nèi)核態(tài)到用戶態(tài)的切換開銷,并且goroutine摒棄了一些golang用不到的一些os thread的系統(tǒng)調(diào)用,創(chuàng)建代價小。

我們可以一瞬間創(chuàng)建很多個goroutine,這是相當容易的。

乍一看,這與題目完全不符,前面說了那么多,難道不是鼓勵我們多創(chuàng)建goroutine嗎?不不不,goroutine確實很好用,但是如果不加以限制,很有可能出現(xiàn)其他的不可預(yù)料的錯誤。

比如在web領(lǐng)域中, 一個連接,在linux/unix下就相當于是打開了一個文件,占用一個文件描述符。但是系統(tǒng)會規(guī)定文件描述符的上限,我們可以使用ulimit -n來進行查看,如果我們遵循量大就好的話,那么一擁而上的請求連接會瞬間報錯。

2018/06/30 10:09:54 dial tcp :8080: socket: too many open files

上面這條報錯信息源于我寫的一個循環(huán)請求的工具

package main
import (
  "sync"
  "net"
  "strconv"
  "fmt"
  "log"
)
const (
  MAX_CONCURRENCY = 10000 
)
var waitGroup sync.WaitGroup
func main(){
  concurrency()
  waitGroup.Wait()
}
//進行網(wǎng)絡(luò)io
func request(currentCount int){
  fmt.Println("request" + strconv.Itoa(currentCount) + "\r")
  conn, err := net.Dial("tcp",":8080")
  if err != nil { log.Fatal(err) }
  defer conn.Close()
  defer waitGroup.Done()
}
//并發(fā)請求
func concurrency(){
  for i := 0;i < MAX_CONCURRENCY;i++ {
    waitGroup.Add(1)
    go request(i)
  }
}

用go建立一個服務(wù)端很簡單,我這里簡單的貼下server的代碼

package main
import (
  "io"
  "os"
  "fmt"
  "net"
)
func checkErr(err error){
  if err != nil { fmt.Fprintln(os.Stderr, err) }
}
func main() {
  listener, err := net.Listen("tcp",":8080")
  checkErr(err)
  for {
    conn, err := listener.Accept()
    checkErr(err)
    go func(conn net.Conn){ 
      _, err := io.WriteString(conn, "welcome!") 
      checkErr(err)
      defer conn.Close()
    }(conn)
  }
}

現(xiàn)在回到主題,我們可以看到一擁而上其實也有壞處,想要解決這一問題,我們可以限制同一時間的并發(fā)數(shù)量,可以利用channel來達到這一點,這有點類似于信號量(Semaphore)

創(chuàng)建一個帶緩存的channel,其中CHANNEL_CACHE為同一時間的最大并發(fā)量

想簡單的說一下為什么這里chan的類型要用一個空的struct,這是因為在這個場景下(限制同一時間的并發(fā)量),通過channel傳輸?shù)臄?shù)據(jù)的類型并不重要,我們只需要通過做一個通知效果就行了(就像你通知你朋友起床,你只用閃個電話,而不用實際的接通,省去了電話費的開銷),這里的空的struct實際上是不占任何空間的,因此這里選用空的struct

const (
  CHANNEL_CACHE = 200
)
var tmpChannel = make(chan struct{}, CHANNEL_CACHE)

在與服務(wù)器建立連接的地方這樣寫(是不是很類似于信號量)

tmpChan <- struct{}{}
conn, err := net.Dial("tcp",":8080")
<- tmpChan

這樣同一時間的并發(fā)量就由CHANNEL_CACHE限制下來

經(jīng)過循環(huán)開啟的goroutine在請求服務(wù)器之前會向channel發(fā)送消息,如果緩存滿了,那么說明已經(jīng)有CHANNEL_CACHE個goroutine在進行與服務(wù)器的連接,接著就會阻塞在這里,等待其中一個goroutine處理完之后,從channel中讀出一個空的struct,這時阻塞的地方向channel發(fā)送一個空struct,就可以與服務(wù)器建立連接了

下面貼一下全部的代碼

package main
import (
  "sync"
  "net"
  "strconv"
  "fmt"
  "log"
)
const (
  MAX_CONCURRENCY = 10000 
  CHANNEL_CACHE = 200
)
var tmpChan = make(chan struct{}, MAX_CONCURRENCY)
var waitGroup sync.WaitGroup
func main(){
  concurrency()
  waitGroup.Wait()
}
//進行網(wǎng)絡(luò)io
func request(currentCount int){
  fmt.Println("request" + strconv.Itoa(currentCount) + "\r")
  tmpChan <- struct{}{}
  conn, err := net.Dial("tcp",":8080")
  <- tmpChan
  if err != nil { log.Fatal(err) }
  defer conn.Close()
  defer waitGroup.Done()
}
//并發(fā)
func concurrency(){
  for i := 0;i < MAX_CONCURRENCY;i++ {
    waitGroup.Add(1)
    go request(i)
	}
}

這樣就可以愉快的進行并發(fā)了!??!

補充:Golang限制N個并發(fā)同時運行

我就廢話不多說了,大家還是直接看代碼吧~

package main 
import (
  "fmt"
  "sync"
  "time"
) 
var wg sync.WaitGroup 
func main() {
  var wg sync.WaitGroup
 
  sem := make(chan struct{}, 2) // 最多允許2個并發(fā)同時執(zhí)行
  taskNum := 10
 
  for i := 0; i < taskNum; i++ {
    wg.Add(1)
 
    go func(id int) {
      defer wg.Done()
 
      sem <- struct{}{}    // 獲取信號
      defer func() { <-sem }() // 釋放信號
 
      // do something for task
      time.Sleep(time.Second * 2)
      fmt.Println(id, time.Now())
    }(i)
  }
  wg.Wait()
}

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

相關(guān)文章

  • Go語言實現(xiàn)文件上傳

    Go語言實現(xiàn)文件上傳

    這篇文章主要為大家詳細介紹了Go語言實現(xiàn)文件上傳,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Go語言web框架Gin響應(yīng)客戶端的方式

    Go語言web框架Gin響應(yīng)客戶端的方式

    Gin是一個用Go語言編寫的web框架,它是一個類似于martini但擁有更好性能的API框架, 由于使用了httprouter,速度提高了近40倍,本文給大家介紹了Go語言web框架Gin響應(yīng)客戶端有哪些方式,文中有詳細的代碼示例供大家參考,需要的朋友可以參考下
    2024-10-10
  • 使用go語言解析xml的實現(xiàn)方法(必看篇)

    使用go語言解析xml的實現(xiàn)方法(必看篇)

    下面小編就為大家?guī)硪黄褂胓o語言解析xml的實現(xiàn)方法(必看篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • 一文詳細談?wù)凣oLang的panic和error

    一文詳細談?wù)凣oLang的panic和error

    說是初識,并不是說第一次使用error和panic包,而是第一次特地去了解golang中的這兩個機制,下面這篇文章主要給大家介紹了關(guān)于如何通過一文詳細談?wù)凣oLang中panic和error的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Go語言struct類型詳解

    Go語言struct類型詳解

    這篇文章主要介紹了Go語言struct類型詳解,struct是一種數(shù)據(jù)類型,可以用來定義自己想的數(shù)據(jù)類型,需要的朋友可以參考下
    2014-10-10
  • Go構(gòu)建高性能的事件管理器實例詳解

    Go構(gòu)建高性能的事件管理器實例詳解

    這篇文章主要為大家介紹了Go構(gòu)建高性能的事件管理器實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • golang函數(shù)的返回值實現(xiàn)

    golang函數(shù)的返回值實現(xiàn)

    本文主要介紹了golang函數(shù)的返回值實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • go語言中讀取配置文件的方法總結(jié)

    go語言中讀取配置文件的方法總結(jié)

    這篇文章主要為大家詳細介紹了go語言中讀取配置文件的幾個常見方法,文中的示例代碼講解詳細,具有一定的借鑒價值,需要的小伙伴可以參考下
    2023-08-08
  • 通過手機案例理解Go設(shè)計模式之裝飾器模式的功能屬性

    通過手機案例理解Go設(shè)計模式之裝飾器模式的功能屬性

    這篇文章主要為大家介紹了Go設(shè)計模式之裝飾器模式的功能屬性,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Go 面向包新提案透明文件夾必要性分析

    Go 面向包新提案透明文件夾必要性分析

    這篇文章主要為大家介紹了Go 面向包新提案,透明文件夾必要性分析,看看是否合適加進 Go 特性中,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11

最新評論