Go語言(Golang)高併發處理思路

2021-10-08 11:44:42 字數 3495 閱讀 1209

go語言作為新興的語言,最近發展勢頭很是迅猛,其最大的特點就是原生支援併發。它使用的是「協程(goroutine)模型」,和傳統基於 os 執行緒和程序實現不同,go語言的併發是基於使用者態的併發,這種併發方式就變得非常輕量,能夠輕鬆執行幾萬併發邏輯。go 的併發屬於 csp 併發模型的一種實現,csp 併發模型的核心概念是:「不要通過共享記憶體來通訊,而應該通

過通訊來共享記憶體」。這在 go 語言中的實現就是 goroutine 和 channel。

在一些場景下,有大規模請求(十萬或百萬級qps),我們處理的請求可能不需要立馬知道結果,例如資料的打點,檔案的上傳等等。這時候我們需要非同步化處理。常用的方法有使用resque、mq、rabbitmq等。這裡我們在golang語言裡進行設計實踐。

在go語言原生併發的支援下,我們可以直接使用乙個goroutine(如下方式)去並行處理這個請求。但是,這種方法明顯有些不好的地方,我們沒法控制goroutine產生數量,如果處理程式稍微耗時,在單機萬級十萬級qps請求下,goroutine大規模爆發,記憶體暴漲,處理效率會很快下降甚至引發程式崩潰。

緩衝佇列一定程度上了提高了併發,但也是治標不治本,大規模併發只是推遲了問題的發生時間。當請求速度遠大於佇列的處理速度時,緩衝區很快被打滿,後面的請求一樣被堵塞了。

只用緩衝佇列不能解決根本問題,這時候我們可以參考一下執行緒池的概念,定乙個工作池(協程池),來限定最大goroutine數目。每次來新的job時,從工作池裡取出乙個可用的worker來執行job。這樣一來即保障了goroutine的可控性,也盡可能大的提高了併發處理能力。

首先,我們定義乙個job的介面, 具體內容由具體job實現;

// --------------------------- job ---------------------

type job inte***ce

然後定義一下job佇列和work池型別,這裡我們work池也用golang的channel實現。

type jobqueue chan job

// --------------------------- worker ---------------------

type worker struct

// --------------------------- workerpool ---------------------

type workerpool struct

package main

import (

"fmt"

"runtime"

"time"

)//定義乙個實現job介面的資料

type score struct

//定義對資料的處理

func (s *score) do()

func main()

p.jobqueue

} }()

//迴圈列印輸出當前程序的goroutine 個數

for

}// --------------------------- job ---------------------

type job inte***ce

type jobqueue chan job

// --------------------------- worker ---------------------

type worker struct

func newworker() worker

}//啟動參與程式執行的go程數量

func (w worker) run(wq chan jobqueue)

} }()

}// --------------------------- workerpool ---------------------

type workerpool struct

func newworkerpool(workerlen int) *workerpool

}func (wp *workerpool) run()

// 迴圈獲取可用的worker,往worker中寫job

go func()

} }()

}

執行效果:

核心**:

思考:臨時變數 worker是channel,沒有讀操作,只有寫操作。為什麼沒有發生死鎖現象?

select
分別輸出臨時變數worker、w.jobchan,**如下:

// 迴圈獲取可用的worker,往worker中寫job

go func()

} }()

//啟動參與程式執行的go程數量

func (w worker) run(wq chan jobqueue)

} }()

}

輸出效果為:

結果發現worker、w.jobchan是同一位址(指向的位址一樣)。所以 在

worker
job :=
由於worker、w.jobchan是對同一資料進行操作,所以臨時變數worker不會發生死鎖現象。

說明:也可以將核心內容封裝成乙個庫,以後直接呼叫即可。

知識點說明:

1、 位址引用參考:

2、對應channel讀寫的操作(ch為chan 的型別):

ch
資料型別:=
ch1

go語言高併發channel詳解

go語言中channel可以理解是乙個先進先出的佇列,通過管道進行通訊。csp 模型 傳統的併發模型主要分為 actor 模型和 csp 模型,csp 模型全稱為 communicating sequential processes,csp 模型由併發執行實體 程序,執行緒或協程 和訊息通道組成,實...

處理高併發

這個我感覺都不是做開發來考慮的,但是估計面試需要。做查詢的時候會對查詢的表加上共享鎖。做更改的時候對錶加排它鎖。這個進行多個表更新查詢的時候x需要加鎖abc,y加鎖cba。現在x加了a需要c,y加了c需要a,就形成死鎖了。可以對錶建立乙個臨時表,臨時表不需要加鎖。還可以通過建立檔案組,來處理高併發,...

高併發處理

真實的支撐複雜業務場景的高併發系統架構其實是非常複雜的。比如說每秒百萬併發的中介軟體系統 每日百億請求的閘道器系統 瞬時每秒幾十萬請求的秒殺大促系統 支撐幾億使用者的大規模高並發電商平台架構,等等。為了支撐高併發請求,在系統架構的設計時,會結合具體的業務場景和特點,設計出各種複雜的架構,這需要大量底...