github.com/bruceshao/lockfree@v1.1.3-0.20230816090528-e89824c0a6e9/producer_test.go (about)

     1  /*
     2   * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   */
     7  
     8  package lockfree
     9  
    10  import (
    11  	"fmt"
    12  	"math/rand"
    13  	"os"
    14  	"reflect"
    15  	"sync"
    16  	"sync/atomic"
    17  	"testing"
    18  	"time"
    19  	"unsafe"
    20  )
    21  
    22  const (
    23  	GoSize   = 5000
    24  	SchPerGo = 10000
    25  )
    26  
    27  type longEventHandler[T uint64] struct {
    28  	count int32
    29  	ts    time.Time
    30  }
    31  
    32  func (h *longEventHandler[T]) OnEvent(v uint64) {
    33  	atomic.AddInt32(&h.count, 1)
    34  	if h.count == 1 {
    35  		h.ts = time.Now()
    36  	}
    37  	fmt.Println("consumer ", v)
    38  	//if v%1000000 == 0 {
    39  	//	fmt.Printf("read %d\n", v)
    40  	//}
    41  	if h.count == GoSize*SchPerGo {
    42  		tl := time.Since(h.ts)
    43  		fmt.Printf("read time = %d ms\n", tl.Milliseconds())
    44  	}
    45  }
    46  
    47  func TestAA(t *testing.T) {
    48  	var (
    49  		t1_10us     = uint64(0) // 1-10微秒
    50  		t10_100us   = uint64(0) // 10-100微秒
    51  		t100_1000us = uint64(0) // 100-1000微秒
    52  		t1_10ms     = uint64(0) // 1-10毫秒
    53  		t10_100ms   = uint64(0) // 10-100毫秒
    54  		t100_ms     = uint64(0) // 大于100毫秒
    55  		slower      = uint64(0)
    56  		counter     = uint64(0)
    57  	)
    58  	eh := &longEventHandler[uint64]{}
    59  	//queue, err := NewProducer[uint64](1024*1024, 1, eh, &SleepWaitStrategy{
    60  	//	t: time.Nanosecond * 1,
    61  	//})
    62  	disruptor := NewLockfree[uint64](1024*1024*128, eh,
    63  		NewSleepBlockStrategy(time.Microsecond))
    64  	disruptor.Start()
    65  	producer := disruptor.Producer()
    66  	var wg sync.WaitGroup
    67  	wg.Add(GoSize)
    68  	totalS := time.Now()
    69  	for i := 0; i < GoSize; i++ {
    70  		go func() {
    71  			for j := 0; j < SchPerGo; j++ {
    72  				x := atomic.AddUint64(&counter, 1)
    73  				ts := time.Now()
    74  				err := producer.Write(x)
    75  				if err != nil {
    76  					panic(err)
    77  				}
    78  				tl := time.Since(ts)
    79  				ms := tl.Microseconds()
    80  				if ms > 1 {
    81  					atomic.AddUint64(&slower, 1)
    82  					if ms < 10 { // t1_10us
    83  						atomic.AddUint64(&t1_10us, 1)
    84  					} else if ms < 100 {
    85  						atomic.AddUint64(&t10_100us, 1)
    86  					} else if ms < 1000 {
    87  						atomic.AddUint64(&t100_1000us, 1)
    88  					} else if ms < 10000 {
    89  						atomic.AddUint64(&t1_10ms, 1)
    90  					} else if ms < 100000 {
    91  						atomic.AddUint64(&t10_100ms, 1)
    92  					} else {
    93  						atomic.AddUint64(&t100_ms, 1)
    94  					}
    95  				}
    96  			}
    97  			wg.Done()
    98  		}()
    99  	}
   100  	wg.Wait()
   101  	totalL := time.Since(totalS)
   102  	fmt.Printf("write total time = [%d ms]\n", totalL.Milliseconds())
   103  	fmt.Println("----- write complete -----")
   104  	time.Sleep(time.Second * 3)
   105  	disruptor.Close()
   106  	fmt.Printf("slow ratio = %.2f \n", float64(slower)*100.0/float64(counter))
   107  	fmt.Printf("quick ratio = %.2f \n", float64(counter-slower)*100.0/float64(counter))
   108  	fmt.Printf("[<1us][%d] \n", counter-slower)
   109  	fmt.Printf("[1-10us][%d] \n", t1_10us)
   110  	fmt.Printf("[10-100us][%d] \n", t10_100us)
   111  	fmt.Printf("[100-1000us][%d] \n", t100_1000us)
   112  	fmt.Printf("[1-10ms][%d] \n", t1_10ms)
   113  	fmt.Printf("[10-100ms][%d] \n", t10_100ms)
   114  	fmt.Printf("[>100ms][%d] \n", t100_ms)
   115  }
   116  
   117  func TestB(t *testing.T) {
   118  	var x = uint64(100)
   119  	typeOf := reflect.TypeOf(x)
   120  	fmt.Println(typeOf)
   121  	fmt.Println(os.Getpagesize())
   122  }
   123  
   124  func TestC(t *testing.T) {
   125  	x := 128 - unsafe.Sizeof(uint64(0))%128
   126  	fmt.Println(x)
   127  }
   128  
   129  func TestProducer_WriteWindow(t *testing.T) {
   130  	eh := &sleepEventHandler[uint64]{
   131  		sm: time.Second,
   132  	}
   133  	disruptor := NewLockfree[uint64](1, eh,
   134  		NewSleepBlockStrategy(time.Microsecond))
   135  	disruptor.Start()
   136  	producer := disruptor.Producer()
   137  	// 写入10个数:0-9
   138  	// 预期结果,0可以写入,写入后在1ms内被取走,此时0会在等待1s后被打印,但由于ringbuffer有空位,所以1可以被写入
   139  	// 1写入后一直无法被取走,因为在等待1s内0的打印,后续其他值均无法被写入,因为1导致ringbuffer满了
   140  	for i := 0; i < 10; i++ {
   141  		ww := producer.WriteWindow()
   142  		if ww <= 0 {
   143  			// 表示不能写入,丢弃
   144  			fmt.Println("discard ", i , " window ", ww)
   145  		} else {
   146  			// 实际写入
   147  			producer.Write(uint64(i))
   148  		}
   149  		// 为了给予consumer时间取走
   150  		time.Sleep(time.Millisecond)
   151  	}
   152  	// 为了可以看到打印的结果
   153  	time.Sleep(3 * time.Second)
   154  	disruptor.Close()
   155  }
   156  
   157  func TestWriteTimeout(t *testing.T) {
   158  	var counter = uint64(0)
   159  	// 写入超时,如何使用
   160  	eh := &longSleepEventHandler[uint64]{}
   161  	disruptor := NewLockfree[uint64](2, eh, NewSleepBlockStrategy(time.Microsecond))
   162  	disruptor.Start()
   163  	producer := disruptor.Producer()
   164  	// 假设有10个写g
   165  	var wg sync.WaitGroup
   166  	for i := 0; i < 100; i++ {
   167  		wg.Add(1)
   168  		go func() {
   169  			for j := 0; j < 100; j++ {
   170  				v := atomic.AddUint64(&counter, 1)
   171  				wc, exist, err := producer.WriteTimeout(v, time.Millisecond)
   172  				if err != nil {
   173  					return
   174  				}
   175  				if !exist {
   176  					// 重复写入1次,写入不成功则丢弃重新写其他的
   177  					if ok, _ := producer.WriteByCursor(v, wc); ok {
   178  						continue
   179  					}
   180  					fmt.Println("discard ", v)
   181  					// 重新生成值,一直等待写入
   182  					v = atomic.AddUint64(&counter, 1)
   183  					for {
   184  						if ok, _ := producer.WriteByCursor(v, wc); ok {
   185  							fmt.Println("write ", v, " with x times")
   186  							break
   187  						}
   188  						// 写入不成功则休眠,防止CPU暴增
   189  						time.Sleep(100 * time.Microsecond)
   190  					}
   191  				} else {
   192  					fmt.Println("write ", v, " with 1 time")
   193  				}
   194  			}
   195  			wg.Done()
   196  		}()
   197  	}
   198  	wg.Wait()
   199  	time.Sleep(3 * time.Second)
   200  	disruptor.Close()
   201  }
   202  
   203  
   204  // sleepEventHandler 休眠性质的事件处理器
   205  type sleepEventHandler[T uint64] struct {
   206  	sm time.Duration
   207  }
   208  
   209  func (h *sleepEventHandler[T]) OnEvent(v uint64) {
   210  	time.Sleep(h.sm)
   211  	fmt.Println("consumer ", v)
   212  }
   213  
   214  type longSleepEventHandler[T uint64] struct {
   215  	count int32
   216  }
   217  
   218  func (h *longSleepEventHandler[T]) OnEvent(v uint64) {
   219  	// 每次处理都会进行随机休眠,可以导致消费端变慢
   220  	intn := rand.Intn(1000)
   221  	time.Sleep(time.Duration(intn * 1000))
   222  	fmt.Println("consumer count ", atomic.AddInt32(&h.count, 1))
   223  }