Benchmarking Goroutines in Go with Code

Benchmarking Goroutines in Go involves measuring the performance of concurrent code execution. It’s important to note that the actual performance can vary based on factors such as hardware, operating system, and the specific nature of the tasks being performed. Here’s a simple example of a benchmark comparing the execution time of a task with and without Goroutines:

package main

import (
    "fmt"
    "sync"
    "time"
)

// Function to simulate a time-consuming task
func timeConsumingTask() {
    time.Sleep(100 * time.Millisecond)
}

// Non-concurrent version of the task
func nonConcurrentTask() {
    for i := 0; i < 10; i++ {
        timeConsumingTask()
    }
}

// Concurrent version of the task using Goroutines
func concurrentTask(wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        go timeConsumingTask()
    }
}

func main() {
    // Benchmark the non-concurrent version
    start := time.Now()
    nonConcurrentTask()
    elapsed := time.Since(start)
    fmt.Printf("Non-concurrent execution time: %s\n", elapsed)

    // Benchmark the concurrent version
    start = time.Now()
    var wg sync.WaitGroup
    wg.Add(10)
    concurrentTask(&wg)
    wg.Wait()
    elapsed = time.Since(start)
    fmt.Printf("Concurrent execution time: %s\n", elapsed)
}

In this example, we have a simple time-consuming task (timeConsumingTask) that simulates a computational workload. The nonConcurrentTask function performs this task sequentially ten times. The concurrentTask function, on the other hand, uses Goroutines to perform the same task concurrently.

The benchmark measures the execution time of both the non-concurrent and concurrent versions. Note that this is a simplified example, and actual benchmarks may involve more sophisticated scenarios, such as handling shared data, network operations, or complex computations.

To run benchmarks in Go, you can use the built-in testing package along with the go test command. Benchmarks are functions with a specific naming convention, such as BenchmarkXXX, and are executed with the -bench flag:

package main

import (
    "testing"
)

func BenchmarkNonConcurrentTask(b *testing.B) {
    for i := 0; i < b.N; i++ {
        nonConcurrentTask()
    }
}

func BenchmarkConcurrentTask(b *testing.B) {
    var wg sync.WaitGroup
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        wg.Add(10)
        concurrentTask(&wg)
        wg.Wait()
    }
}

Save the benchmarks in a file named benchmark_test.go and run the following command:

go test -bench=.

This will execute the benchmarks and provide insights into the performance of the non-concurrent and concurrent versions of the task. Keep in mind that the actual results may vary based on your system’s capabilities and workload characteristics.

This is also a great blog to check out on Goroutines – and another, here.

So I’m actually writing this as I’m building a subdomain enumeration tool that will query the top 60000 plus DNS resolvers, and run simultaneously. Should be fun, and the goal will be to see if I can build a tool faster than MASSdns, although that could be hard.

Here’s another good post I wrote on goRoutines for vulnerability discovery

Find it interesting