package main import ( "fmt" "time" ) // Message represents a simple data structure type Message struct { ID int Data string } func main() { const ( batchSize = 3 batchDelay = 200 * time.Millisecond ) inputCh := make(chan Message, 10) // Buffered channel for incoming messages // Simulate a producer sending messages rapidly go func() { for i := 0; i < 10; i++ { inputCh <- Message{ID: i, Data: fmt.Sprintf("Item %d", i)} time.Sleep(50 * time.Millisecond) } close(inputCh) }() // Batch processor go func() { var batch []Message timer := time.NewTimer(batchDelay) defer timer.Stop() for { select { case msg, ok := <-inputCh: if !ok { // Input channel closed, process any remaining batch if len(batch) > 0 { processBatch(batch) } fmt.Println("Batch processor exiting.") return } batch = append(batch, msg) // If batch size reached, process immediately if len(batch) >= batchSize { processBatch(batch) batch = nil // Clear batch timer.Reset(batchDelay) // Reset timer after processing } else { // Reset timer if not processing immediately, to wait for more messages or timeout // Stop any existing timer first to avoid multiple expirations if !timer.Stop() { <-timer.C // Drain the channel if timer already fired } timer.Reset(batchDelay) } case <-timer.C: // Timer fired, process whatever is in the batch if len(batch) > 0 { processBatch(batch) batch = nil // Clear batch } timer.Reset(batchDelay) // Reset timer for next cycle } } }() time.Sleep(1 * time.Second) // Let producer and processor run fmt.Println("Main: Program finished.") } func processBatch(msgs []Message) { fmt.Printf("Processing batch of %d messages: ", len(msgs)) for _, msg := range msgs { fmt.Printf("%d ", msg.ID) } fmt.Println() time.Sleep(50 * time.Millisecond) // Simulate work }