github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/queue/delay_queue_test.go (about) 1 package queue 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 "unsafe" 8 9 "github.com/stretchr/testify/assert" 10 11 "github.com/benz9527/xboot/lib/hrtime" 12 "github.com/benz9527/xboot/lib/infra" 13 ) 14 15 func TestDelayQueueAlignmentAndSize(t *testing.T) { 16 ctx := context.TODO() 17 dq := NewArrayDelayQueue[*employee](ctx, 32) 18 t.Logf("dq aligment size: %d\n", unsafe.Alignof(dq)) 19 prototype := dq.(*ArrayDelayQueue[*employee]) 20 t.Logf("dq prototype alignment size: %d\n", unsafe.Alignof(prototype)) 21 t.Logf("dq prototype wake up channel alignment size: %d\n", unsafe.Alignof(prototype.wakeUpC)) 22 t.Logf("dq prototype priority queue alignment size: %d\n", unsafe.Alignof(prototype.pq)) 23 t.Logf("dq prototype sleeping alignment size: %d\n", unsafe.Alignof(prototype.sleeping)) 24 25 t.Logf("dq size: %d\n", unsafe.Sizeof(dq)) 26 t.Logf("dq prototype size: %d\n", unsafe.Sizeof(prototype)) 27 t.Logf("dq prototype wake up channel size: %d\n", unsafe.Sizeof(prototype.wakeUpC)) 28 t.Logf("dq prototype priority queue size: %d\n", unsafe.Sizeof(prototype.pq)) 29 t.Logf("dq prototype sleeping size: %d\n", unsafe.Sizeof(prototype.sleeping)) 30 } 31 32 func TestArrayDelayQueue_PollToChan(t *testing.T) { 33 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 34 defer cancel() 35 36 dq := NewArrayDelayQueue[*employee](ctx, 32) 37 receiver := infra.NewSafeClosableChannel[*employee]() 38 go dq.PollToChan( 39 func() int64 { 40 return time.Now().UTC().UnixMilli() 41 }, 42 receiver, 43 ) 44 45 ms := time.Now().UTC().UnixMilli() 46 dq.Offer(&employee{age: 10, name: "p0", salary: ms + 110}, ms+110) 47 dq.Offer(&employee{age: 101, name: "p1", salary: ms + 501}, ms+501) 48 dq.Offer(&employee{age: 10, name: "p2", salary: ms + 155}, ms+155) 49 dq.Offer(&employee{age: 200, name: "p3", salary: ms + 210}, ms+210) 50 dq.Offer(&employee{age: 3, name: "p4", salary: ms + 60}, ms+60) 51 dq.Offer(&employee{age: 1, name: "p5", salary: ms + 110}, ms+110) 52 dq.Offer(&employee{age: 5, name: "p6", salary: ms + 250}, ms+250) 53 dq.Offer(&employee{age: 200, name: "p7", salary: ms + 301}, ms+301) 54 55 expectedCount := 8 56 actualCount := 0 57 defer func() { 58 assert.LessOrEqual(t, actualCount, expectedCount) 59 }() 60 61 time.AfterFunc(300*time.Millisecond, func() { 62 _ = receiver.Close() 63 }) 64 itemC := receiver.Wait() 65 for { 66 select { 67 default: 68 if receiver.IsClosed() { 69 return 70 } 71 case item, ok := <-itemC: 72 if !ok { 73 t.Log("receiver channel closed") 74 time.Sleep(100 * time.Millisecond) 75 return 76 } 77 now := time.Now().UTC().UnixMilli() 78 t.Logf("current time ms: %d, item: %v, diff: %d\n", now, item, now-item.salary) 79 actualCount++ 80 } 81 } 82 } 83 84 func BenchmarkDelayQueue_PollToChan(b *testing.B) { 85 86 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.N+10)*time.Millisecond) 87 defer cancel() 88 89 dq := NewArrayDelayQueue[*employee](ctx, 32) 90 91 receiver := infra.NewSafeClosableChannel[*employee]() 92 go dq.PollToChan( 93 func() int64 { 94 return time.Now().UTC().UnixMilli() 95 }, 96 receiver, 97 ) 98 go func(ctx context.Context) { 99 <-ctx.Done() 100 _ = receiver.Close() 101 }(ctx) 102 ms := time.Now().UTC().UnixMilli() 103 b.ResetTimer() 104 for i := 0; i < b.N; i++ { 105 dq.Offer(&employee{age: i, name: "p", salary: int64(i)}, ms+int64(i)) 106 } 107 108 defer func() { 109 b.StopTimer() 110 b.ReportAllocs() 111 }() 112 itemC := receiver.Wait() 113 for { 114 select { 115 default: 116 if receiver.IsClosed() { 117 return 118 } 119 case <-itemC: 120 121 } 122 } 123 } 124 125 func BenchmarkDelayQueue_PollToChan_zone(b *testing.B) { 126 127 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.N+10)*time.Millisecond) 128 defer cancel() 129 130 dq := NewArrayDelayQueue[*employee](ctx, 32) 131 132 receiver := infra.NewSafeClosableChannel[*employee]() 133 go dq.PollToChan( 134 func() int64 { 135 zone := time.FixedZone("CST", int(hrtime.TzUtc0Offset)) 136 return time.Now().In(zone).UnixMilli() 137 }, 138 receiver, 139 ) 140 go func(ctx context.Context) { 141 <-ctx.Done() 142 _ = receiver.Close() 143 }(ctx) 144 zone := time.FixedZone("CST", int(hrtime.TzUtc0Offset)) 145 ms := time.Now().In(zone).UnixMilli() 146 b.ResetTimer() 147 for i := 0; i < b.N; i++ { 148 dq.Offer(&employee{age: i, name: "p", salary: int64(i)}, ms+int64(i)) 149 } 150 151 defer func() { 152 b.StopTimer() 153 b.ReportAllocs() 154 }() 155 itemC := receiver.Wait() 156 for { 157 select { 158 default: 159 if receiver.IsClosed() { 160 return 161 } 162 case <-itemC: 163 164 } 165 } 166 }