美文网首页
go 抽象的生产者消费者模型

go 抽象的生产者消费者模型

作者: 跑马溜溜的球 | 来源:发表于2020-07-09 18:29 被阅读0次

这是一个单一生产者,多个消费者的模型。对之前的代码做了改进。

目的:

  1. 包装成包的形式。包的名子叫pc, producer/consumer的简写。
  2. 使用者只需要写自己实际的生产逻辑和消费逻辑即可。

1. 实现

package pc

import (
    "sync"
)

type Task interface {
}

type AbstructPC struct {
    ConsumerNum int
    ChanLen     int
    Tasks       chan Task
    Consumer    func(Task)
    Producer    func(chan Task)
    wg          sync.WaitGroup
}

func (a *AbstructPC) Init(cl int, cn int, p func(chan Task), c func(Task)) {
    a.ChanLen = cl
    a.ConsumerNum = cn
    a.Tasks = make(chan Task, a.ConsumerNum)
    a.Producer = p
    a.Consumer = c
}

func (a *AbstructPC) producerDispatch() {
    defer close(a.Tasks)

    a.Producer(a.Tasks)
}

func (a *AbstructPC) consumerDispatch() {
    for i := 0; i < a.ConsumerNum; i++ {
        a.wg.Add(1)
        go func() {
            defer a.wg.Done()
            for task := range a.Tasks {
                a.Consumer(task)
            }
        }()
    }

    a.wg.Wait()
}

func (a *AbstructPC) Run() {
    go a.producerDispatch()
    a.consumerDispatch()
}

思路:

想实现类似抽象类的功能,于是在AbstructPC中预置了两个空函数

    Consumer    func(Task)
    Producer    func(chan Task)

使用者需要实现这两个方法,并在初始化时(Init)将其以参数形式传入。如果使用者未实现这两个方法,运行时会报错。

这个实现也许这不是最佳的方式,但对于初学者的我,目前只能想到这样的方式了>_<|||

2. 使用

2.1 安装

代码放到了github, 所以可以这样安装:

go get -u github.com/qmhball/gopc

当然也可以直接将上面代码放到$GOPATH/gopc/下,注意不同的方式,import时的写法会有点区别。

2.2 需要自定的内容

  1. 实际task的数据结构
  2. 实际生产函数
func Producer(Tasks chan pc.Task) {}
  1. 实际消费函数
func Consumer(task pc.Task) {}
  1. 消费者个数,通道长度

2.3 示例

该示例自定义实际数据格式

type Person struct {}

生产者生产了10条数据,将其json encode后放入通道,消费者取出后json decode输出。main中的几行代码是pc的调用demo。

package main

import (
    "fmt"
    "pc"
    "strconv"
)

type Person struct {
    Name string
    Age  int
}

//实际生产逻辑
func Producer(Tasks chan pc.Task) {
    p := Person{}
    for i := 0; i < 10; i++ {
        p.Name = "Person" + strconv.Itoa(i)
        p.Age = i + 10
        //Task是空接口,Person默认实现了它,自然可以直接放入Task类型的通道
        Tasks <- p
    }
}

//实际消费数据逻辑
func Consumer(task pc.Task) {
    //通过断言将task转为Person类型,不能直接使用task.Name, task,Age
    p := task.(Person)
    fmt.Printf("consum task:%s, %d\n", p.Name, p.Age)
}

func main() {
    var mypc pc.AbstructPC
    chanLen := 50
    consumerNum := 20
    mypc.Init(chanLen, consumerNum, Producer, Consumer)
    mypc.Run()
}

使用时,唯一需要注意的是Consumer中取到task数据后,要使用断言将其转为你真实的数据类型。

相关文章

网友评论

      本文标题:go 抽象的生产者消费者模型

      本文链接:https://www.haomeiwen.com/subject/fjgscktx.html