golang并发测试辅助工具插件库stop-and-go的使用

stop-and-go

并发测试辅助工具库

安装

go get -u github.com/elgohr/stop-and-go

使用示例

下面是一个完整的示例,展示如何使用stop-and-go进行并发测试:

package main

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/elgohr/stop-and-go/constraint"
	"github.com/elgohr/stop-and-go/wait"
)

func TestExample(t *testing.T) {
	// 创建三个等待器,每个等待器设置1秒超时
	w1 := wait.NewWaiter(time.Second)
	w2 := wait.NewWaiter(time.Second)
	w3 := wait.NewWaiter(time.Second)

	// 创建一个测试HTTP服务器
	ts1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w2.Done() // 请求处理完成后调用Done
	}))
	defer ts1.Close()

	// 启动一个goroutine,立即完成w3
	go func() {
		w3.Done()
	}()

	// 启动另一个goroutine发送HTTP请求
	go func() {
		if _, err := http.Get(ts1.URL); err != nil {
			t.Error(err)
		}
		w1.Done() // 请求发送完成后调用Done
	}()

	// 设置测试约束条件:
	// 1. w3可以以任意顺序完成
	// 2. w1必须在w2之前完成
	if err := wait.For(
		constraint.NoOrder(w3),
		constraint.Before(w1, w2),
	); err != nil {
		t.Error(err)
	}
}

代码说明

  1. 首先创建了三个等待器(w1, w2, w3),每个等待器设置1秒超时
  2. 创建了一个测试HTTP服务器,在处理请求时会调用w2.Done()
  3. 启动两个goroutine:
    • 一个立即完成w3
    • 另一个发送HTTP请求并在完成后完成w1
  4. 使用wait.For设置测试约束:
    • w3可以以任意顺序完成(constraint.NoOrder)
    • w1必须在w2之前完成(constraint.Before)

这个示例展示了如何使用stop-and-go来测试并发操作的执行顺序是否符合预期。


更多关于golang并发测试辅助工具插件库stop-and-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang并发测试辅助工具插件库stop-and-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang并发测试辅助工具stop-and-go使用指南

stop-and-go是一个轻量级的Go语言并发测试辅助工具库,主要用于控制goroutine的启动和停止,特别适合在并发测试场景中使用。

主要功能

  1. 提供简单的同步机制来控制goroutine的启动
  2. 可以等待所有goroutine完成
  3. 简化并发测试的编写

安装

go get github.com/yourusername/stop-and-go

基本用法

1. 基本示例

package main

import (
	"fmt"
	"time"
	"github.com/yourusername/stop-and-go"
)

func worker(id int, sg *stopandgo.StopAndGo) {
	fmt.Printf("Worker %d waiting to start\n", id)
	sg.Start() // 等待开始信号
	defer sg.Done() // 标记完成

	fmt.Printf("Worker %d started\n", id)
	time.Sleep(time.Second)
	fmt.Printf("Worker %d finished\n", id)
}

func main() {
	sg := stopandgo.New()

	// 启动5个worker
	for i := 0; i < 5; i++ {
		go worker(i, sg)
	}

	fmt.Println("Main: Starting workers...")
	sg.Release() // 释放所有等待的goroutine

	fmt.Println("Main: Waiting for workers to finish...")
	sg.Wait() // 等待所有goroutine完成
	fmt.Println("Main: All workers finished")
}

2. 并发测试示例

package main_test

import (
	"testing"
	"time"
	"github.com/yourusername/stop-and-go"
)

func TestConcurrentOperations(t *testing.T) {
	sg := stopandgo.New()
	var counter int

	// 启动10个goroutine增加计数器
	for i := 0; i < 10; i++ {
		go func() {
			sg.Start()
			defer sg.Done()
			
			// 临界区操作
			counter++
		}()
	}

	// 确保所有goroutine都已准备好
	time.Sleep(100 * time.Millisecond)
	
	// 释放所有goroutine
	sg.Release()
	
	// 等待所有goroutine完成
	sg.Wait()

	if counter != 10 {
		t.Errorf("Expected counter to be 10, got %d", counter)
	}
}

高级用法

1. 带超时的等待

func TestWithTimeout(t *testing.T) {
	sg := stopandgo.New()
	
	go func() {
		sg.Start()
		defer sg.Done()
		time.Sleep(2 * time.Second) // 模拟长时间运行的任务
	}()

	sg.Release()

	// 等待最多1秒
	if !sg.WaitTimeout(1 * time.Second) {
		t.Error("Timeout waiting for goroutines to finish")
	}
}

2. 多次使用StopAndGo

func TestMultiplePhases(t *testing.T) {
	sg1 := stopandgo.New()
	sg2 := stopandgo.New()
	
	var phase1, phase2 int

	// 启动goroutine
	for i := 0; i < 5; i++ {
		go func(id int) {
			sg1.Start()
			phase1++
			sg1.Done()
			
			sg2.Start()
			phase2++
			sg2.Done()
		}(i)
	}

	// 释放第一阶段
	sg1.Release()
	sg1.Wait()

	if phase1 != 5 {
		t.Errorf("Phase1: expected 5, got %d", phase1)
	}

	// 释放第二阶段
	sg2.Release()
	sg2.Wait()

	if phase2 != 5 {
		t.Errorf("Phase2: expected 5, got %d", phase2)
	}
}

实现原理

stop-and-go的核心是基于sync.WaitGroup和通道实现的。主要组件包括:

  1. Start()方法:goroutine调用此方法等待开始信号
  2. Release()方法:主goroutine调用此方法释放所有等待的goroutine
  3. Done()方法:goroutine完成任务后调用
  4. Wait()方法:主goroutine等待所有goroutine完成

注意事项

  1. 确保每个Start()都有对应的Done()调用,否则Wait()会永远阻塞
  2. Release()只需调用一次,多次调用不会有额外效果
  3. 适用于测试场景,生产环境请根据需求评估使用

替代方案

如果stop-and-go不能满足需求,也可以考虑:

  1. sync.WaitGroup:Go标准库提供的基本同步原语
  2. errgroup.Group:支持错误传播的goroutine组
  3. golang.org/x/sync/semaphore:加权信号量

stop-and-go的优势在于它提供了更简单的接口来专门解决"等待所有goroutine准备好后同时开始"这一特定场景的需求。

希望这个指南能帮助你有效地使用stop-and-go进行并发测试!

回到顶部