間違った説明
- goプロジェクトでスクリプトを作成し、main関数を書きました
- モデルを使用するもの
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/[email protected]: invalid version: unknown revision stress/v1.0.5
手動ビルド
- 情報を参照した後、Maven プロジェクトのセカンドパーティ ライブラリと同様に、プロジェクトを手動でビルドしてモジュールをインストールできます。
- まず、go プロジェクトの依存モジュールがどこにインストールされているかを確認します。
$GOPATH/pkg/mod/
ディレクトリの下にある- Maven のローカル リポジトリの .m2 ディレクトリに似ています。モジュールのストレージ構造も同様です
- 次に、
github.com/link1st/go-stress-testing/stress
プロジェクトのソースコードを ダウンロードします。- クローンされたコードはデフォルトで 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/[email protected] main.go
- でもまだうまくいかない
問題の根本
- 必要なパッケージは、
github.com/link1st/go-stress-testing/stress
- このパッケージをどのように解釈するかを明確にしてください
github.com
: モジュールは github から取得されますlink1st
: 著者はlink1stですgo-stress-testing
: go-stress-testingプロジェクト所属stress
: プロジェクトの下のストレスモジュール
- このモジュールを見つけるには github プロジェクトに移動してください
- いいやつです、ストレスモジュールはまったくありません。
最終的解決
別の方法でストレスモジュールの下にソースコードを見つけました。ファイルは合計 4 つあります。
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()
}
シーンゴー
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 ファイルのコードは信頼できないため、実際のアプリケーションの要件に応じてロジックの適応を実行する必要があることに注意してください。