Implementing a Dynamic QPS Load‑Testing Model in Go Using a Goroutine Pool

This article presents a Go‑based dynamic QPS load‑testing framework that leverages a custom goroutine pool, explains the rationale behind reusing goroutines, provides core functions for task execution and console command handling, and includes a complete runnable demo illustrating high‑throughput performance testing.

FunTester
FunTester
FunTester
Implementing a Dynamic QPS Load‑Testing Model in Go Using a Goroutine Pool

When the author previously wrote a Kafka client in Go and discussed channel versus Java thread performance with a follower, the need for a systematic way to benchmark the two arose, leading to the development of a dynamic QPS load‑testing model as a foundational capability.

The article references an existing Go goroutine‑pool implementation and adds a method that can execute a given task a specified number of times (QPS) by batching the executions, typically in groups of ten (the default SingleTimes), to reduce context‑switch overhead.

func (pool *GorotinesPool) ExecuteQps(t func(), qps int) {
    mutiple := qps / pool.SingleTimes
    remainder := qps % pool.SingleTimes
    for i := 0; i < pool.SingleTimes; i++ {
        pool.Execute(func() {
            for i := 0; i < mutiple; i++ {
                t()
            }
        })
    }
    pool.Execute(func() {
        for i := 0; i < remainder; i++ {
            t()
        }
    })
}

The SingleTimes parameter defaults to 10 but can be tuned based on task execution speed, although the author has not yet performed comparative tests.

Control commands are read from the console using a simple loop that reads lines, trims the newline, and passes the input to a handler function.

func HandleInput(handle func(input string) bool) {
    reader := bufio.NewReader(os.Stdin)
    for {
        text, _ := reader.ReadString('
')
        text = strings.Replace(text, "
", "", -1)
        if handle(text) {
            break
        }
    }
}

A demonstration program creates a pool, reads the desired QPS from the console, repeatedly calls ExecuteQps with a logging task, sleeps for a second between iterations, and finally waits for all goroutines to finish.

func main() {
    pool := execute.GetPool(1000, 2, 200, 1)
    var qps int = 1
    go ftool.HandleInput(func(input string) bool {
        put, err := strconv.Atoi(input)
        if err == nil {
            log.Printf("input content: %d", put)
            qps = put
        }
        return false
    })
    for {
        pool.ExecuteQps(func() {
            log.Println(ftool.Date())
        }, qps)
        ftool.Sleep(1000)
    }
    pool.Wait()
}

The author notes that using main is necessary because Go unit tests cannot handle interactive console input, and observes that Go’s ability to pass functions as parameters feels smoother than Java’s multiple function objects or Groovy’s closures.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

GoQPSgoroutine poolperformance-testing
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.