Golang代码搜集-资源池管理

忘是亡心i 2021-09-14 13:32 478阅读 0赞

这段代码来自《Go语言实战》第7.2节,演示如何编写一个资源池,可用于数据库连接等。原代码资源管理的效果并不明显,笔者对测试用代码进行了修改,使效果更明显。下面直接上代码。

  1. //资源池
  2. package pool
  3. import (
  4. "errors"
  5. "io"
  6. "log"
  7. "sync"
  8. )
  9. // Pool 管理一组可以安全地在多个goroutine间共享的资源
  10. // 被共享的资源必须实现 io.Closer接口
  11. type Pool struct {
  12. m sync.Mutex
  13. resources chan io.Closer
  14. factory func() (io.Closer, error)
  15. closed bool
  16. }
  17. // 资源池已经关闭
  18. var ErrPoolClosed = errors.New("Pool has been closed.")
  19. // 输入资源池size太小
  20. var ErrPoolSizeTooSmall = errors.New("Pool size too small")
  21. // New创建一个用来管事的资源池
  22. func New(fn func() (io.Closer, error), size uint) (*Pool, error) {
  23. if size <= 0 {
  24. return nil, ErrPoolSizeTooSmall
  25. }
  26. return &Pool{
  27. factory: fn,
  28. resources: make(chan io.Closer, size),
  29. }, nil
  30. }
  31. // Acquire 从池中获取一个资源
  32. func (p *Pool) Acquire() (io.Closer, error) {
  33. select {
  34. case r, ok := <-p.resources:
  35. if !ok {
  36. return nil, ErrPoolClosed
  37. }
  38. log.Println("Acquire:", " Shared Resource")
  39. return r, nil
  40. default:
  41. //没有空闲资源,提供新资源
  42. log.Println("Acquire:", " New Resource")
  43. return p.factory()
  44. }
  45. }
  46. func (p *Pool) Release(r io.Closer) {
  47. //保证本操作和close操作的安全
  48. p.m.Lock()
  49. defer p.m.Unlock()
  50. //如果资源池已经关闭,则关闭当前资源
  51. if p.closed {
  52. r.Close()
  53. return
  54. }
  55. select {
  56. //试图将这资源放入队列
  57. case p.resources <- r:
  58. log.Println("Release:", "In Queue")
  59. default:
  60. //如果队列已满,则关闭这个资源
  61. log.Println("Release:", "Closing")
  62. r.Close()
  63. }
  64. }
  65. //Close 资源池停止工作,并关闭所有现有的资源
  66. func (p *Pool) Close() {
  67. //保证本操作和Release操作的安全
  68. p.m.Lock()
  69. defer p.m.Unlock()
  70. //如果已经关闭,则什么也不做
  71. if p.closed {
  72. return
  73. }
  74. //关闭资源池
  75. p.closed = true
  76. //关闭通道,必须先关闭
  77. close(p.resources)
  78. //关闭资源
  79. for r := range p.resources {
  80. r.Close()
  81. }
  82. }
  83. //使用示例
  84. package main
  85. import (
  86. "fmt"
  87. "io"
  88. "log"
  89. "math/rand"
  90. "pool"
  91. "sync"
  92. "sync/atomic"
  93. "time"
  94. )
  95. var (
  96. maxGoroutines = 10
  97. pooledResources uint = 5
  98. )
  99. // dbConnection 模拟共享资源
  100. type dbConnection struct {
  101. Id int32
  102. }
  103. // 实现io.Closer接口
  104. func (db *dbConnection) Close() error {
  105. log.Println("Close:Connection", db.Id)
  106. return nil
  107. }
  108. // 用来给第个链接一个独一无二的id
  109. var idCounter int32
  110. func createConn() (io.Closer, error) {
  111. id := atomic.AddInt32(&idCounter, 1)
  112. log.Println("Create:New Conn", id)
  113. return &dbConnection{id}, nil
  114. }
  115. func main() {
  116. rand.Seed(time.Now().UnixNano())
  117. fmt.Println("This demo presents how to use the pool")
  118. //创建资源池
  119. p, err := pool.New(createConn, pooledResources)
  120. if err != nil {
  121. log.Fatal("Create pool failed")
  122. }
  123. //关闭资源池
  124. defer p.Close()
  125. var wg sync.WaitGroup
  126. wg.Add(maxGoroutines)
  127. for query := 0; query < maxGoroutines; query++ {
  128. go performQueries(query, p, &wg)
  129. //随机等一段时间,否则后而gorountine在获取资源时
  130. //资源池仍没有资源
  131. time.Sleep(time.Duration(rand.Intn(2)) * time.Second)
  132. }
  133. //等待 结束
  134. wg.Wait()
  135. fmt.Printf("Query num:%d, Connection num:%d\n", maxGoroutines, idCounter)
  136. }
  137. func performQueries(query int, p *pool.Pool, wg *sync.WaitGroup) {
  138. defer wg.Done()
  139. //从池里请求一个链接
  140. conn, err := p.Acquire()
  141. if err != nil {
  142. log.Fatal(err)
  143. }
  144. defer p.Release(conn)
  145. //模拟查询
  146. time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
  147. log.Printf("QID[%d] CID[%d]\n", query, conn.(*dbConnection).Id)
  148. }

发表评论

表情:
评论列表 (有 0 条评论,478人围观)

还没有评论,来说两句吧...

相关阅读

    相关 资源搜集的方法

    授人以鱼不如授人以渔,下面我来说说一些寻找学习资源的方法 1、谷歌搜索引擎 利用谷歌搜索引擎的高级语法,可以定位到你想搜索的各种资源。常见的高级语法有 sit

    相关 Golang代码搜集-资源管理

    这段代码来自《Go语言实战》第7.2节,演示如何编写一个资源池,可用于数据库连接等。原代码资源管理的效果并不明显,笔者对测试用代码进行了修改,使效果更明显。下面直接上代码。