【Go并发】Go协程池

协程池是固定有数量goroutine的工作池Pool,Pool中的goroutine并发地执行任务。

一、定义任务

在实现协程池前需要明确任务是啥,这里模拟一个场景:将一个文件的文本转化为小写并输出到一个新的文件中。

1、定义任务接口

​ 任务接口定义了单个任务需要执行的任务内容,如这里的Do()方法

type Tasker interface {
	Do()
}
2、实现任务接口
  • 具体的任务是将一个大文件的文本input.txt转换为小写并输出到output.txt文件中。
  • 定义具体的任务结构体
type Task struct {
	text    string      // 单次处理的文本
	results chan string // 结果channel,各任务之间共享信道
}
  • 定义具体执行的任务
func (t *Task) Do() {
   result := strings.ToUpper(t.text)
   t.results <- result
}
二、定义协程池

协程池需要定义池的容量,任务消息队列,通信队列。

1、定义协程池
type Pool struct {
   cap  int              // 协程池的容量
   jobs chan Tasker      // 任务通道
   done chan interface{} // 各个G结束信号的消息通道
}
2、定义协程池相关操作

(1)构造函数

func NewTask(cap int) *Pool {
   return &Pool{
      cap:  cap,
      jobs: make(chan Tasker),
      done: make(chan interface{}, cap),
   }
}

(2)池运行函数

func (p *Pool) Run() {
   for i := 0; i < p.cap; i++ {  // 创建cap个G
      go p.run()
   }
}

(3)池中的单个G运行函数

func (p *Pool) run() {
   for task := range p.jobs {
      task.Do()
   }
   p.done <- nil // 执行结束之后写入完成信号
}

(4)关闭池函数

func (p *Pool) Close() {
   close(p.jobs)
   for i := 0; i < p.cap; i++ {
      <-p.done // 等待各个G结束
   }
}
三、主函数
func main() {
   const outPath = "output.txt"
   const inPath = "testCase01"
   f, e := os.Open(inPath)
   if e != nil {
      panic(e)
   }
   defer f.Close()
   lines := make(chan string)
   outs := make(chan string)
   pool := NewPool(3)
   go func() { // 读者G,将文本按行输入到channel
      defer close(lines)
      rder := bufio.NewReader(f)
      for {
         l, _, e := rder.ReadLine()
         if e != nil {
            break
         }
         lines <- string(l)
      }
   }()

   go func() { // 任务注册G,将lines的内容注册任务。
      defer pool.Close()
      defer close(outs)
      for line := range lines {
         pool.Register(&Task{
            text:    line,
            results: outs,
         })
      }
   }()

   pool.Run()  // 开启协程池。
   fOut, e := OpenFile(outPath)
   if e != nil {
      panic(e)
   }
   w := bufio.NewWriter(fOut)
   for o := range outs {
      w.WriteString(o)
      w.WriteByte('\n')
      w.Flush()
   }
}

// OpenFile 打开文件,不存在则创建
func OpenFile(out string) (*os.File, error) {
   if _, e := os.Stat(out); os.IsNotExist(e) {
      return os.Create(out)
   } else {
      return os.OpenFile(out, os.O_WRONLY, 0666)
   }
}
  • 代码实现了多个G并发地执行任务,如何对该代码进一步优化,待下回分解…
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值