亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

Go語言之并發示例-Pool(二)

發布時間:2020-07-18 18:35:55 來源:網絡 閱讀:554 作者:baby神 欄目:數據庫

針對這個資源池管理的一步步都實現了,而且做了詳細的講解,下面就看下整個示例代碼,方便理解。

package commonimport (
    "errors"
    "io"
    "sync"
    "log")//一個安全的資源池,被管理的資源必須都實現io.Close接口type Pool struct {
    m       sync.Mutex
    res     chan io.Closer
    factory func() (io.Closer, error)
    closed  bool}var ErrPoolClosed = errors.New("資源池已經被關閉。")//創建一個資源池func New(fn func() (io.Closer, error), size uint) (*Pool, error) {
    if size <= 0 { 
           return nil, errors.New("size的值太小了。")
    }    
    return &Pool{
        factory: fn,
        res:     make(chan io.Closer, size),
    }, nil}//從資源池里獲取一個資源func (p *Pool) Acquire() (io.Closer,error) { 
   select {
       case r,ok := <-p.res:
        log.Println("Acquire:共享資源")       
        if !ok {
                    return nil,ErrPoolClosed
        }        
        return r,nil
    default:
        log.Println("Acquire:新生成資源")        
        return p.factory()
    }}
 //關閉資源池,釋放資源func (p *Pool) Close() {
    p.m.Lock()
    defer p.m.Unlock()    
    if p.closed { 
           return
    }

    p.closed = true

    //關閉通道,不讓寫入了
    close(p.res)    //關閉通道里的資源
    for r:=range p.res {
        r.Close()
    }}func (p *Pool) Release(r io.Closer){
    //保證該操作和Close方法的操作是安全的
    p.m.Lock()    
    defer p.m.Unlock()   

     //資源池都關閉了,就省這一個沒有釋放的資源了,釋放即可
    if p.closed {
        r.Close()        
        return 
    }    
    select {
    case p.res <- r:
        log.Println("資源釋放到池子里了")    
    default:
        log.Println("資源池滿了,釋放這個資源吧")
        r.Close()
    }
}


好了,資源池管理寫好了,也知道資源池是如何實現的啦,現在我們看看如何使用這個資源池,模擬一個數據庫連接池吧。

package mainimport (
    "flysnow.org/hello/common"
    "io"
    "log"
    "math/rand"
    "sync"
    "sync/atomic"
    "time")const (    
    //模擬的最大goroutine
    maxGoroutine = 5
    //資源池的大小
    poolRes      = 2)func main() {    
    //等待任務完成
    var wg sync.WaitGroup
    wg.Add(maxGoroutine)

    p, err := common.New(createConnection, poolRes)    

    if err != nil {
        log.Println(err)        
        return
    }    
    //模擬好幾個goroutine同時使用資源池查詢數據
    for query := 0; query < maxGoroutine; query++ { 
       go func(q int) {
            dbQuery(q, p)
            wg.Done()
        }(query)
    }

    wg.Wait()
    log.Println("開始關閉資源池")
    p.Close()}//模擬數據庫查詢func dbQuery(query int, pool *common.Pool) {
    conn, err := pool.Acquire()
    if err != nil {
        log.Println(err)       
         return
    }    
    defer pool.Release(conn)    
    //模擬查詢
    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
    log.Printf("第%d個查詢,使用的是ID為%d的數據庫連接", query, conn.(*dbConnection).ID)}//數據庫連接type dbConnection struct {
    ID int32//連接的標志}//實現io.Closer接口func (db *dbConnection) Close() error {
    log.Println("關閉連接", db.ID)    
    return nil}var idCounter int32//生成數據庫連接的方法,以供資源池使用func createConnection() (io.Closer, error) {   
    //并發安全,給數據庫連接生成唯一標志
    id := atomic.AddInt32(&idCounter, 1)    
    return &dbConnection{id}, nil
}


這時我們測試使用資源池的例子,首先定義了一個結構體dbConnection,它只有一個字段,用來做唯一標記。然后dbConnection實現了io.Closer接口,這樣才可以使用我們的資源池。


createConnection函數對應的是資源池中的factory字段,用來創建數據庫連接dbConnection的,同時為其賦予了一個為止的標志


接著我們就同時開了 5 個goroutine,模擬并發的數據庫查詢dbQuery,查詢方法里,先從資源池獲取可用的數據庫連接,用完后再釋放。


這里我們會創建 5 個數據庫連接,但是我們設置的資源池大小只有 2 ,所以再釋放了 2 個連接后,后面的 3 個連接會因為資源池滿了而釋放不了,一會我們看下輸出的打印信息就可以看到。


最后這個資源連接池使用完之后,我們要關閉資源池,使用資源池的Close方法即可。


2017/04/17 22:25:08 Acquire:新生成資源
2017/04/17 22:25:08 Acquire:新生成資源
2017/04/17 22:25:08 Acquire:新生成資源
2017/04/17 22:25:08 Acquire:新生成資源
2017/04/17 22:25:08 Acquire:新生成資源
2017/04/17 22:25:08 2個查詢,使用的是ID4的數據庫連接
2017/04/17 22:25:08 資源釋放到池子里了
2017/04/17 22:25:08 4個查詢,使用的是ID1的數據庫連接
2017/04/17 22:25:08 資源釋放到池子里了
2017/04/17 22:25:08 3個查詢,使用的是ID5的數據庫連接
2017/04/17 22:25:08 資源池滿了,釋放這個資源吧
2017/04/17 22:25:08 關閉連接 5
2017/04/17 22:25:09 1個查詢,使用的是ID3的數據庫連接
2017/04/17 22:25:09 資源池滿了,釋放這個資源吧
2017/04/17 22:25:09 關閉連接 3
2017/04/17 22:25:09 0個查詢,使用的是ID2的數據庫連接
2017/04/17 22:25:09 資源池滿了,釋放這個資源吧
2017/04/17 22:25:09 關閉連接 2
2017/04/17 22:25:09 開始關閉資源池
2017/04/17 22:25:09 關閉連接 4
2017/04/17 22:25:09 關閉連接 1


到這里,我們已經完成了一個資源池的管理,并且進行了使用測試。


資源對象池的使用比較頻繁,因為我們想把一些對象緩存起來,以便使用,這樣就會比較高效,而且不會經常調用GC,為此Go為我們提供了原生的資源池管理,防止我們重復造輪子,這就是sync.Pool,我們看下剛剛我們的例子,如果用sync.Pool實現。


package mainimport (
    "log"
    "math/rand"
    "sync"
    "sync/atomic"
    "time")const (    
    //模擬的最大goroutine
    maxGoroutine = 5)func main() {
    //等待任務完成
    var wg sync.WaitGroup
    wg.Add(maxGoroutine)

    p:=&sync.Pool{
        New:createConnection,
    }   
     //模擬好幾個goroutine同時使用資源池查詢數據
    for query := 0; query < maxGoroutine; query++ {
      go func(q int) {
            dbQuery(q, p)
            wg.Done()
        }(query)
    }

    wg.Wait()}//模擬數據庫查詢
func dbQuery(query int, pool *sync.Pool) {    conn:=pool.Get().(*dbConnection)        defer pool.Put(conn)        //模擬查詢    time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)    log.Printf("第%d個查詢,使用的是ID為%d的數據庫連接", query, conn.ID)}//數據庫連接
type dbConnection struct {    ID int32//連接的標志}//實現io.Closer接口
func (db *dbConnection) Close() error {    log.Println("關閉連接", db.ID)    return nil}var idCounter int32//生成數據庫連接的方法,以供資源池使用
func createConnection() interface{} {      //并發安全,給數據庫連接生成唯一標志    id := atomic.AddInt32(&idCounter, 1)    return &dbConnection{ID:id}
}


進行微小的改變即可,因為系統庫沒有提供New這類的工廠函數,所以我們使用字面量創建了一個sync.Pool,注意里面的New字段,這是一個返回任意對象的方法,類似我們自己實現的資源池中的factory字段,意思都是一樣的,都是當沒有可用資源的時候,生成一個。


這里我們留意到系統的資源池是沒有大小限制的,也就是說默認情況下是無上限的,受內存大小限制。


資源的獲取和釋放對應的方法是GetPut,也很簡潔,返回任意對象interface{}


2017/04/17 22:42:43 0個查詢,使用的是ID2的數據庫連接
2017/04/17 22:42:43 2個查詢,使用的是ID5的數據庫連接
2017/04/17 22:42:43 4個查詢,使用的是ID1的數據庫連接
2017/04/17 22:42:44 3個查詢,使用的是ID4的數據庫連接
2017/04/17 22:42:44 1個查詢,使用的是ID3的數據庫連接


關于系統的資源池,我們需要注意的是它緩存的對象都是臨時的,也就說下一次GC的時候,這些存放的對象都會被清除掉。


向AI問一下細節

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

AI

永寿县| 闽清县| 常熟市| 平远县| 河东区| 石景山区| 阿鲁科尔沁旗| 栾川县| 英山县| 通河县| 白城市| 乌拉特后旗| 桐城市| 嘉荫县| 瓮安县| 泉州市| 那坡县| 土默特左旗| 灵武市| 宁安市| 鸡泽县| 康平县| 北碚区| 同心县| 砀山县| 枞阳县| 浙江省| 临朐县| 桂平市| 化州市| 大埔县| 广德县| 安徽省| 天气| 桃园县| 九寨沟县| 托里县| 兴宁市| 莱阳市| 合水县| 阜阳市|