golang不阻塞写协程

package main

import (
    "fmt"
    "time"
    "errors"
    "sync"
    "container/list"
)

type Itask interface {
    Execute()
    EchoID() int
}

type TestTask struct {
    ID int
}

func (t *TestTask) Execute() {
    fmt.Printf("TestTask| task id[%d] execute.\n", t.ID)
}

func (t *TestTask) EchoID() int {
    return t.ID
}

type Queue struct {
    sync.Mutex

    in chan Itask

    out chan Itask

    stopCh chan struct {}

    l *list.List
}

func NewQueue() *Queue {
    q := &Queue {
        in : make(chan Itask),
        out : make(chan Itask),
        stopCh : make(chan struct{}),
        l : list.New(),
    }

    return q
}

// 启动异步消费协程
func (q *Queue) Start() {
    go q.consume()
}

// 消费list中数据 将数据写入channel
func (q *Queue) consume() {
    for {
        if q.l.Len() == 0 {
            fmt.Printf("Queue| q list len is 0.\n")
            select {
            case t := <-q.in:
                q.l.PushBack(t)
            case <-q.stopCh:
                // graceful exit
                if q.l.Len() != 0 {
                    q.out <- q.l.Front().Value.(Itask)
                }

                return
            }
        }

        select {
            case t := <-q.in:
                fmt.Printf("Queue| consume task id[%d].\n", t.EchoID())
                q.l.PushBack(t)
            case q.out <-q.l.Front().Value.(Itask):
                q.l.Remove(q.l.Front())
            case <-q.stopCh:
                taskNum := q.l.Len()

                for i := 0; i < taskNum; i++ {
                    q.out <- q.l.Front().Value.(Itask)
                    q.l.Remove(q.l.Front())
                }

                return
        }
    }
}

// 将数据放入list
func (q *Queue) PutTask(t Itask) error {
    fmt.Printf("Queue| put task id[%d].\n", t.EchoID())
    // 为保证不阻塞 设置超时时间1s
    timeout := time.After(time.Second * 1)

    select {
    case q.in <- t:
        return nil
    case <-timeout:
        return errors.New("Queue| put task failed, timeout.")
    }
}

// 关闭异步消费协程
func (q *Queue) Stop() {
    close(q.stopCh)
}

// block读取channel中数据
func (q *Queue) GetTask() Itask {
    return <-q.out
}

func main() {
    var wg sync.WaitGroup
    q := NewQueue()
    q.Start()

    wg.Add(2)

    go func() {
        for i := 0; i < 10; i++ {
            t := new(TestTask)
            t.ID = i

            q.PutTask(t)
        }
        wg.Done()
    }()

	// 出于简单考虑
	// 工程中生产者消费者需要提供stop功能  
	// 启动时先启动消费者 再启动生产者
	// 关闭时应先stop生产者 后stop消费者
    go func() {
        for i := 0; i < 10; i++ {
            t := q.GetTask()
            t.Execute()
        }
        wg.Done()
    }()

    // 主协程阻塞
    wg.Wait()
    q.Stop()

    return
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值