223 lines
5.5 KiB
Go
223 lines
5.5 KiB
Go
/*
|
||
* 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))
|
||
} |