github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/14_concurrent/disruptor/main.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/smartystreets/go-disruptor"
     6  	"runtime"
     7  	"sync"
     8  	"time"
     9  )
    10  
    11  const (
    12  	RingBufferSize   = 1024 * 64
    13  	RingBufferMask   = RingBufferSize - 1
    14  	ReserveOne       = 1
    15  	ReserveMany      = 16
    16  	ReserveManyDelta = ReserveMany - 1
    17  	DisruptorCleanup = time.Millisecond * 10
    18  )
    19  
    20  var ringBuffer = [RingBufferSize]int64{}
    21  
    22  type countConsumer struct {
    23  	Count           int64
    24  	TotalIterations int64
    25  	WG              sync.WaitGroup
    26  }
    27  
    28  func (cc *countConsumer) Consume(lower, upper int64) {
    29  	for lower <= upper {
    30  		message := ringBuffer[lower&RingBufferMask]
    31  		if message != lower {
    32  			warning := fmt.Sprintf("\nRace condition--Sequence: %d, Message: %d\n", lower, message)
    33  			fmt.Printf(warning)
    34  			panic(warning)
    35  		}
    36  		lower++
    37  		cc.Count++
    38  		//fmt.Printf("count: %d, message: %d\n", cc.Count-1, message)
    39  		if cc.Count == cc.TotalIterations {
    40  			cc.WG.Done()
    41  			return
    42  		}
    43  	}
    44  }
    45  
    46  func main() {
    47  	NumPublishers := runtime.NumCPU()
    48  	totalIterations := int64(1000 * 1000 * 20)
    49  	iterations := totalIterations / int64(NumPublishers)
    50  	totalIterations = iterations * int64(NumPublishers)
    51  
    52  	fmt.Printf("Total: %d,  Iterations: %d, Publisher: %d, Consumer: 1\n", totalIterations, iterations, NumPublishers)
    53  
    54  	runtime.GOMAXPROCS(NumPublishers)
    55  	var consumer = &countConsumer{TotalIterations: totalIterations, Count: 0}
    56  	consumer.WG.Add(1)
    57  
    58  	controller := disruptor.Configure(RingBufferSize).WithConsumerGroup(consumer).BuildShared()
    59  	controller.Start()
    60  	defer controller.Stop()
    61  	var wg sync.WaitGroup
    62  	wg.Add(NumPublishers + 1)
    63  	var sendWG sync.WaitGroup
    64  	sendWG.Add(NumPublishers)
    65  	for i := 0; i < NumPublishers; i++ {
    66  		go func() {
    67  			writer := controller.Writer()
    68  			wg.Done()
    69  			wg.Wait()
    70  			current := disruptor.InitialSequenceValue
    71  			for current < totalIterations {
    72  				current = writer.Reserve(ReserveMany)
    73  				for j := current - ReserveMany + 1; j <= current; j++ {
    74  					ringBuffer[j&RingBufferMask] = j
    75  				}
    76  				writer.Commit(current-ReserveMany, current)
    77  			}
    78  			sendWG.Done()
    79  		}()
    80  	}
    81  	wg.Done()
    82  	t := time.Now().UnixNano()
    83  	wg.Wait() //waiting for ready as a barrier
    84  	fmt.Println("start to publish")
    85  	sendWG.Wait()
    86  	fmt.Println("Finished to publish")
    87  	consumer.WG.Wait()
    88  	fmt.Println("Finished to consume")        //waiting for consumer
    89  	t = (time.Now().UnixNano() - t) / 1000000 //ms
    90  	fmt.Printf("opsPerSecond: %d\n", totalIterations*1000/t)
    91  
    92  }