亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用相同通道的不同呼叫

使用相同通道的不同呼叫

Go
HUH函數 2023-07-31 15:47:38
您使用的 Go 版本是什么(go version)?$ go version 1.13.1最新版本是否會重現此問題?我不知道。您使用什么操作系統和處理器架構(go env)?$ go envGO111MODULE="auto"GOARCH="amd64"GOBIN="/usr/local/go/bin"GOCACHE="/data/xieyixin/.cache/go-build"GOENV="/data/xieyixin/.config/go/env"GOEXE=""GOFLAGS=""GOHOSTARCH="amd64"GOHOSTOS="linux"GONOPROXY=""GONOSUMDB=""GOOS="linux"GOPATH="/data/xieyixin/go"GOPRIVATE=""GOPROXY="http://10.0.12.201:8989/"GOROOT="/usr/local/go"GOSUMDB="sum.golang.org"GOTMPDIR=""GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"GCCGO="gccgo"AR="ar"CC="gcc"CXX="g++"CGO_ENABLED="1"GOMOD="/data/xieyixin/hxagent/go.mod"CGO_CFLAGS="-g -O2"CGO_CPPFLAGS=""CGO_CXXFLAGS="-g -O2"CGO_FFLAGS="-g -O2"CGO_LDFLAGS="-g -O2"PKG_CONFIG="pkg-config"GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build474907248=/tmp/go-build"你做了什么?
查看完整描述

2 回答

?
躍然一笑

TA貢獻1826條經驗 獲得超6個贊

當你的函數退出時,你正在關閉通道ExecCommand。由于您在 Goroutine 中發送消息,因此無法保證該消息會在函數退出之前發送。事實上,我每次跑步都是在之后發生的。如果沒有第一個可推遲的內容,您的測試將正常工作。


? ? defer func() {

? ? ? ? log.Printf("waitDone addr:%v\n", &waitDone)

? ? ? ? log.Printf("close waitdone channel\n")

? ? ? ? close(waitDone) // <- here?

? ? }()


? ? go func() {

? ? ? ? err = cmd.Run()

? ? ? ? log.Printf("waitDone addr:%v\n", &waitDone)

? ? ? ? waitDone <- struct{}{}? // <- and here

? ? }()


由于您已經在使用超時上下文,因此這將非常適合


cmd = exec.CommandContext(ctx, "bash", "-c", "--", command)

// cmd = exec.Command("bash", "-c", "--", command)

這可以使您免于使用這種復雜的邏輯來檢查超時。


查看完整回答
反對 回復 2023-07-31
?
侃侃爾雅

TA貢獻1801條經驗 獲得超16個贊

考慮使用exec.CommandContext而不是自己編寫此代碼。

在命令完成之前上下文超時的情況下,該ExecCommand函數可以在 Run goroutine 發送到通道之前關閉通道。這會引起恐慌。

waitDone由于應用程序在執行后不會收到任何消息close(waitDone),因此關閉通道是沒有意義的。

如果刪除關閉通道的代碼,就會暴露另一個問題。因為是一個無緩沖的通道,所以在超時情況下,waitDoneRun goroutine 將在發送時永遠阻塞。waitDone

調用cmd.Run()啟動一個 goroutine 將數據復制到stdoutstderr。無法保證這些 goroutine 在ExecCommand調用convertStr(stdout)或之前執行完畢convertStr(stderr)。

這是解決所有這些問題的一個方法:

func ExecCommand(command string, timeout time.Duration) (string, error) {

? ? log.Printf("command:%v, timeout:%v", command, timeout)

? ? ctx, cancelFn := context.WithTimeout(context.Background(), timeout)

? ? defer cancelFn()


? ? var stdout, stderr bytes.Buffer


? ? cmd := exec.Command("bash", "-c", "--", command)

? ? cmd.Stdout = &stdout

? ? cmd.Stderr = &stderr

? ? cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}


? ? err := cmd.Start()

? ? if err != nil {

? ? ? ? return "", err

? ? }


? ? go func() {

? ? ? ? <-ctx.Done()

? ? ? ? if ctx.Err() == context.DeadlineExceeded {

? ? ? ? ? ? log.Printf("timeout to kill process, %v", cmd.Process.Pid)

? ? ? ? ? ? syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)

? ? ? ? }

? ? }()


? ? err = cmd.Wait()

? ? var result string

? ? if err != nil {

? ? ? ? result = stderr.String()

? ? } else {

? ? ? ? result = stdout.String()

? ? }

}


查看完整回答
反對 回復 2023-07-31
  • 2 回答
  • 0 關注
  • 153 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號