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  }