gqueue

    使用场景

    该队列是并发安全的,常用于多goroutine数据通信且支持动态队列大小的场景。

    使用方式

    https://godoc.org/github.com/gogf/gf/container/gqueue

    1. package main
    2. import (
    3. "fmt"
    4. "time"
    5. "github.com/gogf/gf/os/gtimer"
    6. "github.com/gogf/gf/container/gqueue"
    7. )
    8. func main() {
    9. q := gqueue.New()
    10. // 数据生产者,每隔1秒往队列写数据
    11. gtimer.SetInterval(time.Second, func() {
    12. v := gtime.Now().String()
    13. q.Push(v)
    14. fmt.Println("Push:", v)
    15. })
    16. // 3秒后关闭队列
    17. q.Close()
    18. })
    19. // 消费者,不停读取队列数据并输出到终端
    20. for {
    21. if v := q.Pop(); v != nil {
    22. } else {
    23. break
    24. }
    25. }
    26. }

    在该示例中,第3秒时关闭队列,这时程序立即退出,因此结果中只会打印2秒的数据。执行后,输出结果为:

    使用队列对象公开的Queue.C属性,结合selectIO复用语法实现对队列的读取。

    1. package main
    2. import (
    3. "fmt"
    4. "github.com/gogf/gf/container/gqueue"
    5. "github.com/gogf/gf/os/gtime"
    6. "github.com/gogf/gf/os/gtimer"
    7. "time"
    8. )
    9. func main() {
    10. // 数据生产者,每隔1秒往队列写数据
    11. gtimer.SetInterval(time.Second, func() {
    12. queue.Push(gtime.Now().String())
    13. })
    14. // 消费者,不停读取队列数据并输出到终端
    15. for {
    16. select {
    17. case v := <-queue.C:
    18. fmt.Println(v)
    19. } else {
    20. return
    21. }
    22. }
    23. }
    24. }

    gqueue的底层基于list链表实现动态大小特性,但是gqueue的使用场景都是多goroutine下的并发安全通信场景。在队列满时存储(限制队列大小时),或者在队列空时读取数据会产生类似channel那样的阻塞效果。

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

    gqueue与标准库channel的性能测试,其中每一次基准测试的b.N值均为20000000,以保证动态队列存取一致防止deadlock:

    1. goos: darwin
    2. goarch: amd64
    3. pkg: github.com/gogf/gf/container/gqueue
    4. Benchmark_Gqueue_StaticPushAndPop-4 20000000 84.2 ns/op
    5. Benchmark_Gqueue_DynamicPush-4 20000000 164 ns/op
    6. Benchmark_Gqueue_DynamicPop-4 20000000 121 ns/op
    7. PASS

    使用起来比channel更加灵活,不仅创建效率高(动态分配内存),不受队列大小限制(也可限定大小)。