91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

利用golang怎么限制同一時間的并發數量

發布時間:2020-12-15 15:37:23 來源:億速云 閱讀:998 作者:Leah 欄目:開發技術

本篇文章給大家分享的是有關利用golang怎么限制同一時間的并發數量,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

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

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

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

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

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

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

package main
import (
  "sync"
  "net"
  "strconv"
  "fmt"
  "log"
)
const (
  MAX_CONCURRENCY = 10000 
)
var waitGroup sync.WaitGroup
func main(){
  concurrency()
  waitGroup.Wait()
}
//進行網絡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()
}
//并發請求
func concurrency(){
  for i := 0;i < MAX_CONCURRENCY;i++ {
    waitGroup.Add(1)
    go request(i)
  }
}

用go建立一個服務端很簡單,我這里簡單的貼下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)
  }
}

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

創建一個帶緩存的channel,其中CHANNEL_CACHE為同一時間的最大并發量

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

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

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

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

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

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

下面貼一下全部的代碼

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()
}
//進行網絡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()
}
//并發
func concurrency(){
  for i := 0;i < MAX_CONCURRENCY;i++ {
    waitGroup.Add(1)
    go request(i)
	}
}

這樣就可以愉快的進行并發了!!!

補充:Golang限制N個并發同時運行

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

package main 
import (
  "fmt"
  "sync"
  "time"
) 
var wg sync.WaitGroup 
func main() {
  var wg sync.WaitGroup
 
  sem := make(chan struct{}, 2) // 最多允許2個并發同時執行
  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()
}

以上就是利用golang怎么限制同一時間的并發數量,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汉源县| 城口县| 平安县| 柘荣县| 通海县| 洞口县| 高碑店市| 临猗县| 老河口市| 天台县| 潼南县| 铜山县| 克拉玛依市| 广宁县| 金川县| 屏东市| 丰城市| 富民县| 通道| 城步| 略阳县| 禄劝| 泸水县| 崇文区| 锦州市| 黑龙江省| 吕梁市| 买车| 库车县| 旬阳县| 西华县| 太湖县| 寿阳县| 青神县| 信阳市| 乐清市| 墨脱县| 潜山县| 宁南县| 德惠市| 五莲县|