Golang中如何测量代码执行时间

Golang中如何测量代码执行时间

package main

import (
	"time"
)

func main() {
	start := time.Now()

	ch := make(chan int)

	go func() {
		for i := 0; i < 100; i++ {
			ch <- i
		}
	}()

	go chanReader(ch, "JHON")
	go chanReader(ch, "DOE")

	elapsed := time.Since(start)
	println(elapsed)
}

func chanReader(ch chan int, name string) {
	for v := range ch {
		println(v, "     FROM    ", name)
		time.Sleep(time.Millisecond * 5)
	}
}

如何测量执行时间?我知道可以使用 start := time.Now() 和 elapsed := time.Since(start),但如果我添加这些代码,主线程会在两个chanReader完成之前结束执行。我还尝试添加var wg sync.WaitGroup但出现了死锁,不知道是什么原因。我想计算使用fun out模式是否更好。


更多关于Golang中如何测量代码执行时间的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你对 WaitGroup 的使用可能不正确。你肯定需要一种方式让工作线程向主例程传递完成或结束信号。只有在接收到信号后,你才能记录完成时间。

更多关于Golang中如何测量代码执行时间的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你关于WaitGroup的想法是正确的,我假设你已经正确实现了它。但即使正确实现了WaitGroup,你也需要终止chanReader()函数中的for-range循环来避免死锁。如果ch通道保持打开状态,for v := range ch循环将永远不知道何时停止请求数据。

要解决这个问题,你需要在发送完所有必需数据后关闭ch通道。以下是我的实现方式:

package main

import (
	"sync"
	"time"
)

var wg sync.WaitGroup

func main() {

	start := time.Now()

	ch := make(chan int)

	go func() {
		for i := 0; i < 100; i++ {
			ch <- i
		}
		// 注意我在这里关闭了通道
		// 这让接收者知道没有更多数据要发送了
		close(ch)
	}()

	wg.Add(2)
	
	go chanReader(ch, "JOHN")
	go chanReader(ch, "DOE")

	wg.Wait()

	elapsed := time.Since(start)

	println(elapsed)
}

func chanReader(ch chan int, name string) {
	defer wg.Done()
	for v := range ch {
		println(v, "     FROM    ", name)
		time.Sleep(time.Millisecond * 5)
	}

}

在Go语言中,测量并发代码执行时间的关键是确保所有goroutine都完成后再计算总时间。你的代码中主goroutine在启动其他goroutine后立即结束,导致测量不准确。

以下是修正后的代码:

package main

import (
	"sync"
	"time"
)

func main() {
	start := time.Now()

	ch := make(chan int)
	var wg sync.WaitGroup

	// 启动生产者goroutine
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < 100; i++ {
			ch <- i
		}
		close(ch) // 关闭channel以通知读取者结束
	}()

	// 启动两个消费者goroutine
	wg.Add(2)
	go chanReader(ch, "JHON", &wg)
	go chanReader(ch, "DOE", &wg)

	// 等待所有goroutine完成
	wg.Wait()

	elapsed := time.Since(start)
	println("Total execution time:", elapsed.String())
}

func chanReader(ch chan int, name string, wg *sync.WaitGroup) {
	defer wg.Done()
	for v := range ch {
		println(v, "     FROM    ", name)
		time.Sleep(time.Millisecond * 5)
	}
}

关键修改点:

  1. 使用sync.WaitGroup来等待所有goroutine完成
  2. 在生产goroutine中关闭channel,这样读取goroutine的range循环会在channel关闭后自动退出
  3. chanReader函数中调用wg.Done()来通知WaitGroup任务完成

关于fan-out模式的性能对比,你可以这样测试:

// 单消费者版本用于对比
func singleReaderBenchmark() {
	start := time.Now()
	
	ch := make(chan int)
	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < 100; i++ {
			ch <- i
		}
		close(ch)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for v := range ch {
			println(v, "     FROM    ", "SINGLE_READER")
			time.Sleep(time.Millisecond * 5)
		}
	}()

	wg.Wait()
	elapsed := time.Since(start)
	println("Single reader time:", elapsed.String())
}

通过比较两种模式的执行时间,你可以确定在特定场景下哪种模式性能更好。

回到顶部