跳到主要内容
版本:2.10.x(Latest)

泛型队列(推荐使用)

v2.10 版本开始,gqueue 提供了泛型队列 TQueue[T],提供类型安全的队列操作,支持先进先出的数据结构。

基本使用

package main

import (
"fmt"
"github.com/gogf/gf/v2/container/gqueue"
)

func main() {
// 创建一个string类型的泛型队列
q := gqueue.NewTQueue[string]()

// 入队
q.Push("apple")
q.Push("banana")
q.Push("orange")

// 获取队列长度
fmt.Println("Length:", q.Len()) // 输出: Length: 3

// 出队
fmt.Println("Pop:", q.Pop()) // 输出: Pop: apple
fmt.Println("Pop:", q.Pop()) // 输出: Pop: banana

// 获取剩余队列长度
fmt.Println("Length:", q.Len()) // 输出: Length: 1
}

生产者-消费者模式

泛型队列特别适合用于生产者-消费者模式的并发场景。

package main

import (
"fmt"
"time"
"github.com/gogf/gf/v2/container/gqueue"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
)

func main() {
q := gqueue.NewTQueue[string]()

// 数据生产者,每隔1秒往队列写数据
gtimer.SetInterval(time.Second, func() {
v := gtime.Now().String()
q.Push(v)
fmt.Println("Push:", v)
})

// 3秒后关闭队列
gtimer.SetTimeout(3*time.Second, func() {
q.Close()
})

// 消费者,不停读取队列数据并输出到终端
for {
if v := q.Pop(); v != nil {
fmt.Println(" Pop:", *v)
} else {
break
}
}
}

泛型队列特点

  1. 类型安全:在编译期就能发现类型错误,避免运行时类型断言失败。
  2. 先进先出:严格按照FIFO顺序处理数据。
  3. 并发安全:内置并发安全机制,适合多goroutine场景。
  4. 动态大小:支持动态队列大小,也可以设置固定大小。
提示

推荐在新项目中使用泛型队列 TQueue[T],它提供了更好的类型安全性和开发体验。

传统队列类型

下面介绍传统的队列类型,这些类型在旧版本中被广泛使用,仍然完全支持。

使用 Queue.Pop

package main

import (
"fmt"
"time"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/container/gqueue"
)

func main() {
q := gqueue.New()

// 数据生产者,每隔1秒往队列写数据
gtimer.SetInterval(time.Second, func() {
v := gtime.Now().String()
q.Push(v)
fmt.Println("Push:", v)
})

// 3秒后关闭队列
gtimer.SetTimeout(3*time.Second, func() {
q.Close()
})

// 消费者,不停读取队列数据并输出到终端
for {
if v := q.Pop(); v != nil {
fmt.Println(" Pop:", v)
} else {
break
}
}

// 第3秒时关闭队列,这时程序立即退出,因此结果中只会打印2秒的数据。 执行后,输出结果为:
// Output:
// Push: 2021-09-07 14:03:00
// Pop: 2021-09-07 14:03:00
// Push: 2021-09-07 14:03:01
// Pop: 2021-09-07 14:03:01
}

使用 Queue.C

package main

import (
"context"
"fmt"
"time"

_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
"github.com/gogf/gf/v2/container/gqueue"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
)

func main() {
queue := gqueue.New()
gtimer.AddTimes(gctx.GetInitCtx(), time.Second, 3, func(ctx context.Context) {
queue.Push(gtime.Now().String())
})
for {
select {
case queueItem := <-queue.C:
fmt.Println(queueItem)

case <-time.After(3 * time.Second):
fmt.Println("timeout, exit loop")
return
}
}
}

元素入队/出队

package main

import (
"fmt"
"time"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/container/gqueue"
)

func main() {
q := gqueue.New()

for i := 0; i < 10; i++ {
q.Push(i)
}

fmt.Println(q.Pop())
fmt.Println(q.Pop())
fmt.Println(q.Pop())

// Output:
// 0
// 1
// 2
}

队列长度

package main

import (
"fmt"
"time"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/container/gqueue"
)

func main() {
q := gqueue.New()

q.Push(1)
q.Push(2)

fmt.Println(q.Len())
// size是len方法的别称
fmt.Println(q.Size())

// May Output:
// 2
// 2
}

队列关闭

package main

import (
"fmt"
"time"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/container/gqueue"
)

func main() {
q := gqueue.New()

for i := 0; i < 10; i++ {
q.Push(i)
}

fmt.Println(q.Pop())
q.Close()
fmt.Println(q.Pop())
fmt.Println(q.Len())

// Output:
// 0
// <nil>
// 0
}

gqueueglist

gqueue 的底层基于 glist 链表实现动态大小特性,在队列满写入数据或在队列空时读取数据会产生阻塞。

glist 是一个并发安全的链表,并可以允许在关闭并发安全特性的时和一个普通的 list 链表无异,在存储和读取数据时不会发生阻塞。