错误描述
- 在 go 项目中创建了一个脚本,编写了一个 main 函数
 - 其中用到了一个 model  
github.com/link1st/go-stress-testing/stress 
import (
    "fmt"
    // "github.com/dji/go-stress-testing/stress"
	"github.com/link1st/go-stress-testing/stress"
    "net/http"
    "time"
)- 在执行   
go run xxx.go的时候,报错 
queries.go:6:2: no required module provides package github.com/link1st/go-stress-testing/stress; to add it:
        go get github.com/link1st/go-stress-testing/stress- 提示使用  
go get github.com/link1st/go-stress-testing/stress命令去下载缺少的模块 - 果不其然,执行之后依旧报错
 
go: github.com/link1st/go-stress-testing/stress: no matching versions for query "upgrade"- 表示该模块没有可用的更新版本
 - 指定版本:
go get github.com/link1st/go-stress-testing/stress@latest - 依旧报错 获取不到目标版本
 
在github上搜索模块版本信息
- 搜索技巧  
language:go model_name如下 - 查看模块版本信息
 
指定版本来安装
go get github.com/link1st/go-stress-testing/stress@v1.0.5- 事情总不会顺利,依旧报错
 
go: github.com/link1st/go-stress-testing/stress@v1.0.4: invalid version: unknown revision stress/v1.0.5
手动build
- 经过查阅资料,可以手动build项目来安装模块,类似于maven项目中的二方库
 
- 首先搞清楚,go项目的依赖模块都安装在了什么位置
 
- 在  
$GOPATH/pkg/mod/目录下 - 类似于 maven 本地仓库的 .m2 目录。模块的存储结构也是类似的
 
- 然后下载 
github.com/link1st/go-stress-testing/stress的项目源码 
- clone下来的代码默认是 master 分支
 git checkout v1.0.5
- 接下来进行 
go build 
- -o: 指定输出文件的名称和路径。
 - -v: 打印出被编译的 Go 包的名称。
 - -a: 强制重新编译所有的包,而不使用缓存中的结果。
 - -race: 启用数据竞争检测器,以识别并报告 Go 程序中的数据竞争问题。
 - -tags: 指定要使用的构建标记。
 
- 完整命令 
go build -o /Users/duzhihao/go/pkg/mod/github.com/link1st/go-stress-testing/stress@v1.0.5 main.go 
- 然而依旧还是不行
 
问题根源
- 需要的包是 
github.com/link1st/go-stress-testing/stress - 清楚如何解释这个包
 
github.com:模块来源于 githublink1st:作者是 link1stgo-stress-testing:归属于项目 go-stress-testingstress:项目下的 stress 模块
- 去github的项目上找一找这个模块
 - 好家伙,压根没有 stress 这个模块,怪不得折腾来,折腾去都搞不定
 
最终解决
通过别的方式找到了stress模块下的源码,一共有四个文件
task.go
package stress
import (
    "context"
    "errors"
)
// Task represents a stress testing task, which consists of a name, a RunFunc function and optional StopFunc function
type Task struct {
    Name      string
    RunFunc   func() error
    StopFunc  func() error
    Context   context.Context
    Cancel    context.CancelFunc
}
// Run runs the Task and returns a TestResult
func (t *Task) Run() *TestResult {
    var requests uint64
    var errors uint64
    for {
        select {
        case <-t.Context.Done():
            return &TestResult{
                Requests: requests,
                Errors:   errors,
            }
        default:
            if err := t.RunFunc(); err != nil {
                errors++
            }
            requests++
        }
    }
}
// NewTask returns a new Task with the given name and RunFunc function
func NewTask(name string, runFunc func() error) *Task {
    ctx, cancel := context.WithCancel(context.Background())
    return &Task{
        Name:     name,
        RunFunc:  runFunc,
        Context:  ctx,
        Cancel:   cancel,
    }
}
// NewTimedTask returns a new Task with the given name, RunFunc function and duration
func NewTimedTask(name string, runFunc func() error, duration int) *Task {
    ctx, cancel := context.WithTimeout(context.Background(), Duration(duration)*time.Second)
    return &Task{
        Name:     name,
        RunFunc:  runFunc,
        StopFunc: cancel,
        Context:  ctx,
        Cancel:   cancel,
    }
}
// Stop stops the Task
func (t *Task) Stop() error {
    if t.StopFunc == nil {
        return errors.New("Stop function is not defined")
    }
    return t.StopFunc()
}scene.go
package stress
import (
    "sync"
    "sync/atomic"
    "time"
)
// Scene represents a stress testing scene, which consists of multiple tasks
type Scene struct {
    Name        string
    Frequency   time.Duration
    Duration    time.Duration
    SetupFunc   func() error
    CleanupFunc func() error
    tasks       []*Task
}
// AddTask adds a new Task to the Scene
func (s *Scene) AddTask(task *Task) {
    s.tasks = append(s.tasks, task)
}
// Run runs the Scene and returns a TestResult
func (s *Scene) Run() *TestResult {
    resCh := make(chan *TestResult)
    wg := sync.WaitGroup{}
    wg.Add(len(s.tasks))
    for _, task := range s.tasks {
        go func(task *Task) {
            defer wg.Done()
            resCh <- task.Run()
        }(task)
    }
    if s.SetupFunc != nil {
        if err := s.SetupFunc(); err != nil {
            panic(err)
        }
    }
    ticker := time.NewTicker(s.Frequency)
    stop := make(chan bool)
    go func() {
        time.Sleep(s.Duration)
        close(stop)
    }()
    var requests uint64
    var errors uint64
loop:
    for {
        select {
        case <-ticker.C:
            for _, task := range s.tasks {
                for i := 0; i < requestsPerTask; i++ {
                    if err := task.RunFunc(); err != nil {
                        atomic.AddUint64(&errors, 1)
                    }
                    atomic.AddUint64(&requests, 1)
                }
            }
        case res := <-resCh:
            atomic.AddUint64(&requests, res.Requests)
            atomic.AddUint64(&errors, res.Errors)
        case <-stop:
            break loop
        }
    }
    ticker.Stop()
    if s.CleanupFunc != nil {
        if err := s.CleanupFunc(); err != nil {
            panic(err)
        }
    }
    wg.Wait()
    elapsed := time.Duration(requests) * time.Second / time.Duration(rps)
    return &TestResult{
        Requests: requests,
        Errors:   errors,
        Rps:      rps,
        Elapsed:  elapsed,
    }
}
// NewScene returns a new Scene with the given name and default settings
func NewScene(name string) *Scene {
    return &Scene{
        Name:      name,
        Frequency: time.Second,
        Duration:  10 * time.Second,
        SetupFunc: func() error {
            return nil
        },
        CleanupFunc: func() error {
            return nil
        },
    }
}test_result.go
package stress
import "time"
// TestResult represents the result of a stress test
type TestResult struct {
    Requests uint64
    Errors   uint64
    Rps      uint64
    Elapsed  time.Duration
}utils.go
package stress
import "time"
const (
    requestsPerTask = 100
    rps             = 100
)
// Duration is an int that can be used with the time package
type Duration int
func (d Duration) String() string {
    return time.Duration(d * time.Second).String()
}需要注意的是,经过实际操作,这几个go源码并不是很可靠,实际应用还需要根据业务需求来具体调整。










