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

使用Go語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的無(wú)界資源池

 更新時(shí)間:2024年05月06日 10:02:07   作者:shark_chili  
本文我們希望通過(guò)go語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的資源池,而這個(gè)資源池的資源包括但不限于數(shù)據(jù)庫(kù)連接池,線程池,協(xié)程池,網(wǎng)絡(luò)連接池,只要這些資源實(shí)現(xiàn)我們指定的關(guān)閉方法,則都可以通過(guò)我們封裝的資源池進(jìn)行統(tǒng)一管理,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),需要的朋友可以參考下

寫(xiě)在文章開(kāi)頭

我們希望通過(guò)go語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的資源池,而這個(gè)資源池的資源包括但不限于:

  • 數(shù)據(jù)庫(kù)連接池
  • 線程池
  • 協(xié)程池
  • 網(wǎng)絡(luò)連接池

只要這些資源實(shí)現(xiàn)我們指定的關(guān)閉方法,則都可以通過(guò)我們封裝的資源池進(jìn)行統(tǒng)一管理,需要簡(jiǎn)單說(shuō)明一下這個(gè)資源池的要求:

  • 需要用戶(hù)指定資源以及資源的創(chuàng)建方法。
  • 當(dāng)協(xié)程通過(guò)Acquire方法獲取資源時(shí),若發(fā)現(xiàn)當(dāng)前池中有資源可以分配則直接返回,若沒(méi)有足夠的資源則基于傳入的創(chuàng)建方法創(chuàng)建一個(gè)全新的資源分配。
  • 支持資源釋放和資源池關(guān)閉。

聽(tīng)起來(lái)很像是Java的無(wú)界線程池,接下來(lái)我們就基于這個(gè)需求實(shí)現(xiàn)一個(gè)版本。

需求落地

給出資源池結(jié)構(gòu)

我們首先需要給出資源池的結(jié)構(gòu),很明顯作為一個(gè)資源池它需要有一個(gè)管理資源池的channel,為了保證多協(xié)程競(jìng)爭(zhēng)資源的協(xié)程安全,我們還需要通過(guò)一把Mutex完成操作互斥,同時(shí)給出創(chuàng)建資源的工廠方法要求這個(gè)工廠方法創(chuàng)建的資源具備資源關(guān)閉能力:

// Pool 定義一個(gè)結(jié)構(gòu)體 包含重量級(jí)鎖 有緩沖區(qū)Chanel 工廠方法 連接池關(guān)閉狀態(tài)
type Pool struct {
 m        sync.Mutex
 resource chan io.Closer
 factory  func() (io.Closer, error)
 closed   bool
}

創(chuàng)建資源池

有個(gè)上述的定義之后,我們的創(chuàng)建方法就很容易實(shí)現(xiàn)了,只需基于外部的size和工廠方法完成Pool成員變量初始化即可:

var ErrPoolClosed = errors.New("連接池已關(guān)閉")


func New(fn func() (io.Closer, error), size uint) (*Pool, error) {
 //判斷size大小是否合法
 if size <= 0 {
  return nil, errors.New("size不合法")
 }
 //基于工廠方法和size創(chuàng)建資源池
 return &Pool{
  resource: make(chan io.Closer, size),
  factory:  fn,
 }, nil

}

獲取資源

當(dāng)協(xié)程需要獲取資源時(shí),會(huì)查看當(dāng)前緩沖通道是否有足夠的資源,如果有則在正確運(yùn)行的情況下返回出去,反之基于我們上文傳入的工廠方法完成資源創(chuàng)建并返回:

func (p *Pool) Acquire() (io.Closer, error) {
 select {
 //如果channel有足夠的資源分配則直接返回
 case r, ok := <-p.resource:
  if !ok {
   log.Println("連接池已關(guān)閉")
   return nil, ErrPoolClosed
  }
  log.Println("拿到連接池共享資源")
  return r, nil
  //基于工廠方法創(chuàng)建全新的資源返回出去
 default:
  log.Println("資源不足,創(chuàng)建新的連接資源")
  return p.factory()
 }

}

釋放與關(guān)閉

這里我們將資源的釋放和關(guān)閉放在一起說(shuō)明,在進(jìn)行資源釋放和關(guān)閉時(shí)我們需要考慮3個(gè)問(wèn)題即:

  • 已關(guān)閉的資源池?zé)o需歸還資源。
  • 正在關(guān)閉資源池時(shí)不可歸還資源。
  • 正在歸還資源時(shí)不可關(guān)閉資源池。

所以進(jìn)行這兩個(gè)操作時(shí),我們需要通過(guò)互斥鎖確保兩個(gè)操作互斥:

// Release 上鎖 設(shè)置方法退出后解鎖 查看當(dāng)前連接池是否已關(guān)閉,若關(guān)閉則直接將資源關(guān)閉 ,反之select查看能否將其存入緩沖區(qū),若可以輸出入隊(duì)成功,反之輸出隊(duì)列已滿(mǎn)
func (p *Pool) Release(r io.Closer) {
 //上鎖確保關(guān)閉和歸還資源操作互斥
 p.m.Lock()
 //函數(shù)退出時(shí)解鎖
 defer p.m.Unlock()
 //如果資源池關(guān)閉則直接將當(dāng)前資源關(guān)閉銷(xiāo)毀
 if p.closed {
  log.Println("連接池已關(guān)閉,直接銷(xiāo)毀當(dāng)前資源")
  r.Close()
 }
 //將連接歸還,如果滿(mǎn)了則直接關(guān)閉銷(xiāo)毀
 select {
 case p.resource <- r:
  log.Println("連接歸還成功")
 default:
  log.Println("連接池已滿(mǎn),資源直接銷(xiāo)毀")
  r.Close()
 }

}

// Close 方法 上鎖 設(shè)置方法退出后解鎖 遍歷所有資源將其關(guān)閉 然后再關(guān)閉連接池
func (p *Pool) Close() {
 p.m.Lock()

 defer p.m.Unlock()

 if p.closed {
  log.Println("連接池已關(guān)閉,直接銷(xiāo)毀當(dāng)前資源")
  return
 }
 //設(shè)置為關(guān)閉
 p.closed = true
 //關(guān)閉資源
 close(p.resource)
 //遍歷資源池資源
 for r := range p.resource {
  r.Close()
 }

}

測(cè)試代碼與輸出

最后我們給出測(cè)試代碼,可以看到我們基于資源池工具類(lèi)模擬數(shù)據(jù)庫(kù)連接池的管理:

//設(shè)置最大協(xié)程數(shù)與資源池?cái)?shù)為24
const maxGoroutines = 24
const poolResources = 24

//創(chuàng)建可關(guān)閉的數(shù)據(jù)庫(kù)連接
type dbConnection struct {
 ID int32
}
//對(duì)應(yīng)的關(guān)閉方法
func (d *dbConnection) Close() error {
 log.Println("當(dāng)前數(shù)據(jù)庫(kù)連接", d.ID, "已關(guān)閉")
 return nil
}

var idCounter int32

func createConnection() (io.Closer, error) {
 id := atomic.AddInt32(&idCounter, 1)
 return &dbConnection{ID: id}, nil
}

func main() {
 //創(chuàng)建maxGoroutines個(gè)WaitGroup
 var wg sync.WaitGroup
 wg.Add(maxGoroutines)
 //傳入createConnection方法和連接池大小poolResources創(chuàng)建數(shù)據(jù)庫(kù)連接池
 p, err := pool.New(createConnection, poolResources)
 if err != nil {
  log.Println(err)
 }
 //創(chuàng)建24個(gè)協(xié)程獲取資源
 for i := 0; i < maxGoroutines; i++ {
  go func(queryParam int) {
   queryData(queryParam, p)
   defer wg.Done()
  }(i)
 }
 //等待操作完成關(guān)閉連接池
 wg.Wait()
 log.Println("查詢(xún)完成")
 p.Close()

}
//queryData 基于連接池Acquire獲取資源,完成后通過(guò)Release歸還資源
func queryData(queryParam int, p *pool.Pool) {

 r, e := p.Acquire()
 if e != nil {
  log.Println(e)
  return
 }

 defer p.Release(r)

 time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
 log.Println("查詢(xún)", queryParam, "使用連接", r.(*dbConnection).ID)
}

同時(shí)我們給出輸出結(jié)果:

2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 資源不足,創(chuàng)建新的連接資源
2024/05/05 23:36:10 查詢(xún) 17 使用連接 14
2024/05/05 23:36:10 連接歸還成功
2024/05/05 23:36:10 查詢(xún) 5 使用連接 5
2024/05/05 23:36:10 連接歸還成功
2024/05/05 23:36:10 查詢(xún) 3 使用連接 2
2024/05/05 23:36:10 連接歸還成功
2024/05/05 23:36:10 查詢(xún) 19 使用連接 19
2024/05/05 23:36:10 連接歸還成功
.......

小結(jié)

到此這篇關(guān)于使用Go實(shí)現(xiàn)一個(gè)簡(jiǎn)單的無(wú)界資源池的文章就介紹到這了,更多相關(guān)Go無(wú)界資源池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang中for循環(huán)的用法示例詳解

    Golang中for循環(huán)的用法示例詳解

    for循環(huán)就是讓一段代碼循環(huán)的執(zhí)行,接下來(lái)通過(guò)本文給大家講解Golang中for循環(huán)的用法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    這篇文章主要介紹了Golang標(biāo)準(zhǔn)庫(kù)binary的相關(guān)資料,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • Golang接口的定義與空接口及斷言的使用示例

    Golang接口的定義與空接口及斷言的使用示例

    在?Golang?中,接口是一種類(lèi)型,它是由一組方法簽名組成的抽象集合。這篇文章主要為大家介紹了Golang接口的具體使用,希望對(duì)大家有所幫助,空接口是特殊形式的接口類(lèi)型,普通的接口都有方法,而空接口沒(méi)有定義任何方法口,也因此,我們可以說(shuō)所有類(lèi)型都至少實(shí)現(xiàn)了空接口
    2023-04-04
  • golang執(zhí)行命令獲取執(zhí)行結(jié)果狀態(tài)(推薦)

    golang執(zhí)行命令獲取執(zhí)行結(jié)果狀態(tài)(推薦)

    這篇文章主要介紹了golang執(zhí)行命令獲取執(zhí)行結(jié)果狀態(tài)的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-11-11
  • Golang標(biāo)準(zhǔn)庫(kù)os/exec執(zhí)行外部命令并獲取其輸出包代碼示例

    Golang標(biāo)準(zhǔn)庫(kù)os/exec執(zhí)行外部命令并獲取其輸出包代碼示例

    這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫(kù)os/exec執(zhí)行外部命令并獲取其輸出包代碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 一文弄懂用Go實(shí)現(xiàn)MCP服務(wù)的示例代碼

    一文弄懂用Go實(shí)現(xiàn)MCP服務(wù)的示例代碼

    本文主要介紹了一文弄懂用Go實(shí)現(xiàn)MCP服務(wù)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04
  • Go語(yǔ)言中重構(gòu)的技巧分享

    Go語(yǔ)言中重構(gòu)的技巧分享

    這篇文章主要來(lái)和大家分享一下Go語(yǔ)言中重構(gòu)的技巧,即如何盡量避免使用 else、break 和 continue,從而讓代碼更透明、更易讀,感興趣的小伙伴可以學(xué)習(xí)一下
    2023-10-10
  • go中的unsafe包及使用詳解

    go中的unsafe包及使用詳解

    Unsafe code是一種繞過(guò)go類(lèi)型安全和內(nèi)存安全檢查的Go代碼。這篇文章主要介紹了go中的unsafe包,需要的朋友可以參考下
    2019-07-07
  • Golang實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能

    Golang實(shí)現(xiàn)斷點(diǎn)續(xù)傳功能

    這篇文章主要為大家詳細(xì)介紹了Golang實(shí)現(xiàn)斷點(diǎn)續(xù)傳、復(fù)制文件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Golang中如何使用lua進(jìn)行擴(kuò)展詳解

    Golang中如何使用lua進(jìn)行擴(kuò)展詳解

    這篇文章主要給大家介紹了關(guān)于Golang中如何使用lua進(jìn)行擴(kuò)展的相關(guān)資料,這是最近在工作中遇到的一個(gè)問(wèn)題,覺(jué)著有必要分享出來(lái)給大家學(xué)習(xí),文中給出了詳細(xì)的示例,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-10-10

最新評(píng)論