/* * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * */ package lockfree import ( "fmt" "math/rand" "os" "reflect" "sync" "sync/atomic" "testing" "time" "unsafe" ) const ( GoSize = 5000 SchPerGo = 10000 ) type longEventHandler[T uint64] struct { count int32 ts time.Time } func (h *longEventHandler[T]) OnEvent(v uint64) { atomic.AddInt32(&h.count, 1) if h.count == 1 { h.ts = time.Now() } fmt.Println("consumer ", v) //if v%1000000 == 0 { // fmt.Printf("read %d\n", v) //} if h.count == GoSize*SchPerGo { tl := time.Since(h.ts) fmt.Printf("read time = %d ms\n", tl.Milliseconds()) } } func TestAA(t *testing.T) { var ( t1_10us = uint64(0) // 1-10微秒 t10_100us = uint64(0) // 10-100微秒 t100_1000us = uint64(0) // 100-1000微秒 t1_10ms = uint64(0) // 1-10毫秒 t10_100ms = uint64(0) // 10-100毫秒 t100_ms = uint64(0) // 大于100毫秒 slower = uint64(0) counter = uint64(0) ) eh := &longEventHandler[uint64]{} //queue, err := NewProducer[uint64](1024*1024, 1, eh, &SleepWaitStrategy{ // t: time.Nanosecond * 1, //}) disruptor := NewLockfree[uint64](1024*1024*128, eh, NewSleepBlockStrategy(time.Microsecond)) disruptor.Start() producer := disruptor.Producer() var wg sync.WaitGroup wg.Add(GoSize) totalS := time.Now() for i := 0; i < GoSize; i++ { go func() { for j := 0; j < SchPerGo; j++ { x := atomic.AddUint64(&counter, 1) ts := time.Now() err := producer.Write(x) if err != nil { panic(err) } tl := time.Since(ts) ms := tl.Microseconds() if ms > 1 { atomic.AddUint64(&slower, 1) if ms < 10 { // t1_10us atomic.AddUint64(&t1_10us, 1) } else if ms < 100 { atomic.AddUint64(&t10_100us, 1) } else if ms < 1000 { atomic.AddUint64(&t100_1000us, 1) } else if ms < 10000 { atomic.AddUint64(&t1_10ms, 1) } else if ms < 100000 { atomic.AddUint64(&t10_100ms, 1) } else { atomic.AddUint64(&t100_ms, 1) } } } wg.Done() }() } wg.Wait() totalL := time.Since(totalS) fmt.Printf("write total time = [%d ms]\n", totalL.Milliseconds()) fmt.Println("----- write complete -----") time.Sleep(time.Second * 3) disruptor.Close() fmt.Printf("slow ratio = %.2f \n", float64(slower)*100.0/float64(counter)) fmt.Printf("quick ratio = %.2f \n", float64(counter-slower)*100.0/float64(counter)) fmt.Printf("[<1us][%d] \n", counter-slower) fmt.Printf("[1-10us][%d] \n", t1_10us) fmt.Printf("[10-100us][%d] \n", t10_100us) fmt.Printf("[100-1000us][%d] \n", t100_1000us) fmt.Printf("[1-10ms][%d] \n", t1_10ms) fmt.Printf("[10-100ms][%d] \n", t10_100ms) fmt.Printf("[>100ms][%d] \n", t100_ms) } func TestB(t *testing.T) { var x = uint64(100) typeOf := reflect.TypeOf(x) fmt.Println(typeOf) fmt.Println(os.Getpagesize()) } func TestC(t *testing.T) { x := 128 - unsafe.Sizeof(uint64(0))%128 fmt.Println(x) } func TestProducer_WriteWindow(t *testing.T) { eh := &sleepEventHandler[uint64]{ sm: time.Second, } disruptor := NewLockfree[uint64](1, eh, NewSleepBlockStrategy(time.Microsecond)) disruptor.Start() producer := disruptor.Producer() // 写入10个数:0-9 // 预期结果,0可以写入,写入后在1ms内被取走,此时0会在等待1s后被打印,但由于ringbuffer有空位,所以1可以被写入 // 1写入后一直无法被取走,因为在等待1s内0的打印,后续其他值均无法被写入,因为1导致ringbuffer满了 for i := 0; i < 10; i++ { ww := producer.WriteWindow() if ww <= 0 { // 表示不能写入,丢弃 fmt.Println("discard ", i , " window ", ww) } else { // 实际写入 producer.Write(uint64(i)) } // 为了给予consumer时间取走 time.Sleep(time.Millisecond) } // 为了可以看到打印的结果 time.Sleep(3 * time.Second) disruptor.Close() } func TestWriteTimeout(t *testing.T) { var counter = uint64(0) // 写入超时,如何使用 eh := &longSleepEventHandler[uint64]{} disruptor := NewLockfree[uint64](2, eh, NewSleepBlockStrategy(time.Microsecond)) disruptor.Start() producer := disruptor.Producer() // 假设有10个写g var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func() { for j := 0; j < 100; j++ { v := atomic.AddUint64(&counter, 1) wc, exist, err := producer.WriteTimeout(v, time.Millisecond) if err != nil { return } if !exist { // 重复写入1次,写入不成功则丢弃重新写其他的 if ok, _ := producer.WriteByCursor(v, wc); ok { continue } fmt.Println("discard ", v) // 重新生成值,一直等待写入 v = atomic.AddUint64(&counter, 1) for { if ok, _ := producer.WriteByCursor(v, wc); ok { fmt.Println("write ", v, " with x times") break } // 写入不成功则休眠,防止CPU暴增 time.Sleep(100 * time.Microsecond) } } else { fmt.Println("write ", v, " with 1 time") } } wg.Done() }() } wg.Wait() time.Sleep(3 * time.Second) disruptor.Close() } // sleepEventHandler 休眠性质的事件处理器 type sleepEventHandler[T uint64] struct { sm time.Duration } func (h *sleepEventHandler[T]) OnEvent(v uint64) { time.Sleep(h.sm) fmt.Println("consumer ", v) } type longSleepEventHandler[T uint64] struct { count int32 } func (h *longSleepEventHandler[T]) OnEvent(v uint64) { // 每次处理都会进行随机休眠,可以导致消费端变慢 intn := rand.Intn(1000) time.Sleep(time.Duration(intn * 1000)) fmt.Println("consumer count ", atomic.AddInt32(&h.count, 1)) }