Golang中如何从goroutine返回
Golang中如何从goroutine返回 我有一个函数返回多个值(字符串,错误)
connStr := s.Url
con, err := sql.Open("postgres", connStr)
if err != nil {
log.Println(err)
return nil, twirp.NewError(twirp.DataLoss, "DB ERROR")
}
defer con.Close()
var resId int32
err = con.QueryRow(`INSERT INTO info(userID, details) VALUES ($1, $2) RETURNING id`, 0, request.GetDetails()).Scan(&resId)
if err != nil {
return nil, err
}
当我将这段代码包装在匿名goroutine中时
go func() {
connStr := s.Url
con, err := sql.Open("postgres", connStr)
if err != nil {
log.Println(err)
return nil, twirp.NewError(twirp.DataLoss, "DB ERROR")
}
defer con.Close()
var resId int32
err = con.QueryRow(`INSERT INTO info(userID, details) VALUES ($1, $2) RETURNING id`, 0, request.GetDetails()).Scan(&resId)
if err != nil {
return nil, err
}
}()
我的返回语句变得无效,我该如何处理这个问题?
更多关于Golang中如何从goroutine返回的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
你的 Go 协程就像是主应用程序中的一个小进程。不要期望通过 return 指令从 Go 协程中返回值 😷 最终可以使用全局变量或通道,就像这个示例中那样 😏
更多关于Golang中如何从goroutine返回的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在我看来,你遇到错误是因为使用了一个会返回值的匿名函数,而 Go 语言并未预期获取该返回值,也不知道如何处理。为什么不给函数命名并相应处理返回值呢?你需要遵循函数必须声明返回类型的规范,即 func() (返回类型)。如果这不是可选项,也可以使用全局变量,在触发返回前更改它们的值。
在Go语言中,goroutine不能直接返回值给调用它的函数。当你在匿名goroutine中使用return语句时,它只会从goroutine自身返回,而不会传递值给外部函数。
以下是几种处理goroutine返回值的方法:
方法1:使用通道(channel)传递结果
type result struct {
resId int32
err error
}
func (s *YourService) yourMethod(request *YourRequest) (*YourResponse, error) {
resultCh := make(chan result, 1)
go func() {
connStr := s.Url
con, err := sql.Open("postgres", connStr)
if err != nil {
log.Println(err)
resultCh <- result{0, twirp.NewError(twirp.DataLoss, "DB ERROR")}
return
}
defer con.Close()
var resId int32
err = con.QueryRow(`INSERT INTO info(userID, details) VALUES ($1, $2) RETURNING id`, 0, request.GetDetails()).Scan(&resId)
resultCh <- result{resId, err}
}()
// 等待goroutine完成并获取结果
res := <-resultCh
if res.err != nil {
return nil, res.err
}
// 使用res.resId构建响应
return &YourResponse{Id: res.resId}, nil
}
方法2:使用sync.WaitGroup和共享变量
import "sync"
func (s *YourService) yourMethod(request *YourRequest) (*YourResponse, error) {
var (
wg sync.WaitGroup
resId int32
dbErr error
)
wg.Add(1)
go func() {
defer wg.Done()
connStr := s.Url
con, err := sql.Open("postgres", connStr)
if err != nil {
log.Println(err)
dbErr = twirp.NewError(twirp.DataLoss, "DB ERROR")
return
}
defer con.Close()
err = con.QueryRow(`INSERT INTO info(userID, details) VALUES ($1, $2) RETURNING id`, 0, request.GetDetails()).Scan(&resId)
dbErr = err
}()
wg.Wait() // 等待goroutine完成
if dbErr != nil {
return nil, dbErr
}
return &YourResponse{Id: resId}, nil
}
方法3:使用context处理超时
import "context"
func (s *YourService) yourMethod(ctx context.Context, request *YourRequest) (*YourResponse, error) {
resultCh := make(chan result, 1)
go func() {
connStr := s.Url
con, err := sql.Open("postgres", connStr)
if err != nil {
log.Println(err)
resultCh <- result{0, twirp.NewError(twirp.DataLoss, "DB ERROR")}
return
}
defer con.Close()
var resId int32
err = con.QueryRow(`INSERT INTO info(userID, details) VALUES ($1, $2) RETURNING id`, 0, request.GetDetails()).Scan(&resId)
resultCh <- result{resId, err}
}()
select {
case res := <-resultCh:
if res.err != nil {
return nil, res.err
}
return &YourResponse{Id: res.resId}, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
推荐使用方法1(通道)或方法3(带上下文的通道),因为它们提供了更好的并发控制和错误处理机制。通道是Go语言中goroutine间通信的首选方式。

