1.使用有缓冲通道 ch:=make(chan interface{},size)
package main
import (
"context"
"fmt"
"sync"
"time"
)
var (
ProducerCnt = 1
ConsumerCnt = 20
ProcessDuration = 10
QueueCapacity = 10
Timeout = 10
)
type Queue struct {
ch chan interface{}
capacity int
wg *sync.WaitGroup
terminate chan struct{}
}
type Task struct {
ID int
Msg string
}
func NewQueue(ctx context.Context, capacity int) *Queue {
q := &Queue{
ch: make(chan interface{}, capacity),
terminate: make(chan struct{}),
capacity: capacity,
wg: &sync.WaitGroup{},
}
return q
}
func Produce(queue *Queue, producerID int) {
defer func() {
fmt.Println("生产者停止退出,id::", producerID)
queue.wg.Done()
}()
loop:
for i := 0; ; i++ {
select {
case _, ok := <-queue.terminate:
if !ok {
close(queue.ch)
break loop
}
default:
task := Task{
ID: producerID,
Msg: fmt.Sprintf("task %d_%d", producerID, i),
}
queue.ch <- task
fmt.Printf("生产: %v\n", task)
}
}
}
func Consume(queue *Queue, consumerID int) {
defer func() {
fmt.Println("comsumer exit:", consumerID)
queue.wg.Done()
}()
for {
val, ok := <-queue.ch
if !ok {
fmt.Printf("消费者退出: %v\n", consumerID)
return
}
time.Sleep(time.Millisecond * time.Duration(ProcessDuration))
fmt.Printf("----------------id:%d, 消费: %v \n", consumerID, val)
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Timeout)*time.Second)
defer cancel()
queue := NewQueue(ctx, QueueCapacity)
for i := 1; i <= ProducerCnt; i++ {
queue.wg.Add(1)
go Produce(queue, i)
}
for i := 1; i <= ConsumerCnt; i++ {
queue.wg.Add(1)
go Consume(queue, i)
}
<-ctx.Done()
println("截止时间到")
close(queue.terminate)
queue.wg.Wait()
fmt.Println("程序退出:", ctx.Err())
}
2.使用条件变量 sync.Cond
package main
import (
"context"
"fmt"
"sync"
"time"
)
var (
ProducerCnt = 1
ConsumerCnt = 10
ProcessDuration = 10
QueueCapacity = 10
Timeout = 2
)
type Queue struct {
data []interface{}
capacity int
lock sync.Mutex
notEmptyCond *sync.Cond
notFullCond *sync.Cond
}
type Task struct {
ID int
Msg string
}
func NewQueue(capacity int) *Queue {
q := &Queue{
data: make([]interface{}, 0, capacity),
capacity: capacity,
}
q.notEmptyCond = sync.NewCond(&q.lock)
q.notFullCond = sync.NewCond(&q.lock)
return q
}
func (q *Queue) Push(val interface{}) {
q.lock.Lock()
defer q.lock.Unlock()
for len(q.data) == q.capacity {
q.notFullCond.Wait()
}
q.data = append(q.data, val)
q.notEmptyCond.Signal()
}
func (q *Queue) Pop() (interface{}, error) {
q.lock.Lock()
defer q.lock.Unlock()
for len(q.data) == 0 {
q.notEmptyCond.Wait()
}
val := q.data[0]
q.data = q.data[1:]
q.notFullCond.Signal()
return val, nil
}
func Produce(queue *Queue, producerID int) {
for i := 0; ; i++ {
task := Task{
ID: producerID,
Msg: fmt.Sprintf("task %d_%d", producerID, i),
}
queue.Push(task)
fmt.Printf("生产: %v\n", task)
}
}
func Consume(queue *Queue, consumerID int) {
for {
val, err := queue.Pop()
if err != nil {
fmt.Printf("消费者退出: %v\n", err)
return
}
time.Sleep(time.Millisecond * time.Duration(ProcessDuration))
fmt.Printf("----------------id:%d, 消费: %v \n", consumerID, val)
}
}
func main() {
queue := NewQueue(QueueCapacity)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Timeout)*time.Second)
defer cancel()
for i := 1; i <= ProducerCnt; i++ {
go Produce(queue, i)
}
for i := 1; i <= ConsumerCnt; i++ {
go Consume(queue, i)
}
<-ctx.Done()
queue.notEmptyCond.Broadcast()
fmt.Println("程序退出:", ctx.Err())
}
3.使用信号量 semephore
package main
import (
"context"
"fmt"
"golang.org/x/sync/semaphore"
"sync"
"time"
)
var (
ProducerCnt = 1
ConsumerCnt = 2
ProcessDuration = 10
QueueCapacity int64 = 10
Timeout = 10
)
type Buffer struct {
data []interface{}
mutex sync.Mutex
empty *semaphore.Weighted
full *semaphore.Weighted
capacity int64
}
func NewBuffer(size int64) *Buffer {
b := &Buffer{
data: make([]interface{}, 0, size),
empty: semaphore.NewWeighted(size),
full: semaphore.NewWeighted(size),
capacity: size,
}
b.full.TryAcquire(size)
return b
}
func (b *Buffer) Push(ctx context.Context, item interface{}) error {
if err := b.empty.Acquire(ctx, 1); err != nil {
return err
}
b.mutex.Lock()
b.data = append(b.data, item)
b.mutex.Unlock()
b.full.Release(1)
return nil
}
func (b *Buffer) Pop(ctx context.Context) (interface{}, error) {
if err := b.full.Acquire(ctx, 1); err != nil {
return nil, err
}
b.mutex.Lock()
item := b.data[0]
b.data = b.data[1:]
b.mutex.Unlock()
b.empty.Release(1)
return item, nil
}
type Task struct {
ID int
Msg string
}
func Produce(ctx context.Context, queue *Buffer, producerID int) {
for i := 0; ; i++ {
task := Task{
ID: producerID,
Msg: fmt.Sprintf("task %d_%d", producerID, i),
}
queue.Push(ctx, task)
fmt.Printf("生产: %v\n", task)
}
}
func Consume(ctx context.Context, queue *Buffer, consumerID int) {
for {
val, err := queue.Pop(ctx)
if err != nil {
fmt.Printf("消费者退出: %v\n", err)
return
}
time.Sleep(time.Millisecond * time.Duration(ProcessDuration))
fmt.Printf("----------------id:%d, 消费: %v \n", consumerID, val)
}
}
func main() {
buffer := NewBuffer(QueueCapacity)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Timeout)*time.Second)
defer cancel()
for i := 1; i <= ProducerCnt; i++ {
go Produce(ctx, buffer, i)
}
for i := 1; i <= ConsumerCnt; i++ {
go Consume(ctx, buffer, i)
}
<-ctx.Done()
fmt.Println("程序退出:", ctx.Err())
}