关于 Golang Go语言中协程的一个问题

发布于 1周前 作者 yuanlaile 来自 Go语言

关于 Golang Go语言中协程的一个问题

需求:

fun main(){

    x1(id string) (objectEntity entity, error) {}
    
    x2(id string) (objectEntity []entity, error) {}
    
    x3(id string) (objectEntity entity, error) {}
}

x1(),x2(),x3()分别是三个互相不关联的 3 个 sql 查询. x1 会返回一个 objectEntity, error, x2 会返回一个[]objectEntity, x3 会返回一个 objectEntity. 我会拿到这 3 个返回值,然后进行拼接.
本来直接使用 goroutine 和 channel 来进行请求. 但是我遇到一个问题, 不管是 x1,x2,x3 进行查询,返回值 都有 error. 大家有什么好的办法吗?


更多关于关于 Golang Go语言中协程的一个问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

18 回复

“不管是 x1,x2,x3 进行查询,返回值 都有 error” ???
有 error 不就是报错了么,不能先处理了 error 再考虑后面拼接的问题么
具体得看你们容错程度,一个或多个出错了就不参与拼接 还是 不能有 error 必须保证全部有结果才能拼接

再另外说一句,既然要同步拼接,根本不需要走协程,同步执行就行了.异步反而更麻烦

更多关于关于 Golang Go语言中协程的一个问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个好像和协程没啥关系,要根据你需求来决定吧,比如某个返回值有 error 时用个默认值来代替

再定义一个 channel 处理 error 呗

搞不懂这为什么是协程的问题

至少写个能跑起来的伪代码,让大家跑一下吧… 要不大家都不知道你的代码是咋样的,也无法给你解决问题

xResult {
obj objectEntity
err Error
}
不过我觉得这法子不太标准

第一: 异步还是有必要的, 假如 x1 需要 0.5s x2 需要 0.5s x3 需要 0.8s. 如果同步执行,就需要 1.8s. 异步查询,0.8s 就可以拿到所有的结果. 第二: 查询有错误,是因为所有的 orm 包在查询的时候,都会返回 error 这个值. 我目前抽出来的函数 都没有直接对 error 进行处理.都是返回正常的结果和 error.然后在外层统一处理.

把[]objectEntity 和 error 合成为一个结构体
golang<br>type A struct {<br> list []objectEntity<br> err error<br>}<br>
然后错误逻辑放到 service 层做处理

不管有没有协程,不都是应该先处理 error?
只要 error 不是 nil
直接返回给调用者处理就行了

我加了伪代码 求

<br>我加了伪代码... 求大家帮忙写个 gorouter<br><br>
func main() {
id := 1
user1, err := x1(id)
if err != nil {
// 处理
}
userList, err := x2(id)
if err != nil {
// 处理
}
user2, err := x3(id)
if err != nil {
// 处理
}

// 然后 user1, userList, user2 进行拼接
}

type User struct {
Id int json:"id"
Name string json:"name"
}

func x1(id int) (User, error) {
var err error
user := User{
Id: 1,
Name: “xx”,
}

return user, err
}

func x2(id int) ([]User, error) {
var err error
user := User{
Id: 1,
Name: “xx”,
}
userList := []User{user, user}

return userList, err
}

func x3(id int) (User, error) {
var err error
var user User
{
}
err = errors.New(“假设出现错误”)

return user, err
}

<br><br>

#7
我不知道你用的什么 orm 包,常用的 gorm 查询结果是不可能有 error 的,除非是查询结果不存在会有个"record not found"的 error

异步这个你说的是对的,如果所有查询都正常的话.
粗略想了下你要用 channel 需要就需要把结果和 error 统一包一个结构体.可能用 sync.WaitGroup 更简单一些.

<br>func main() {<br> id := 1<br> user1, err := x1(id)<br> if err != nil {<br> // 处理<br> }<br> userList, err := x2(id)<br> if err != nil {<br> // 处理<br> }<br> user2, err := x3(id)<br> if err != nil {<br> // 处理<br> }<br><br> // 然后 user1, userList, user2 进行拼接<br>}<br><br>type User struct {<br> Id int `json:"id"`<br> Name string `json:"name"`<br>}<br><br>func x1(id int) (User, error) {<br> var err error<br> user := User{<br> Id: 1,<br> Name: "xx",<br> }<br><br> return user, err<br>}<br><br>func x2(id int) ([]User, error) {<br> var err error<br> user := User{<br> Id: 1,<br> Name: "xx",<br> }<br> userList := []User{user, user}<br><br> return userList, err<br>}<br><br>func x3(id int) (User, error) {<br> var err error<br> var user User<br> {<br> }<br> err = errors.New("假设出现错误")<br><br> return user, err<br>}<br><br>

你这用 waitgroup 最合适了

wg.Add(3)
errCh := make(chan error)
userCh := make(chan *User)

go func(){
defer wg.Done()
user, err := x1()
if err != nil {

}
}()

根本原因还是 error 是什么,对于 error 应该怎么处理,因为三个 err 的含义或者容忍度可能不一样,一起处理感觉是在偷懒。你的问题跟 goroutine 没有什么关系。
一起处理的话上面的那些 xxgroup 的例子可行,但是有点违背 go 的设计原则。因为本质上都是在“通过共享来传递消息”,通过共享几个 data 变量来在 routine 间传递消息不是 golang 推荐的做法。(我不确定现在 golang 还说不说这个设计理念了,好几年没写过 golang 了)
BTW,我觉得你的数据库结构设计的可能有点问题,join 语句效率也没有低到这个程度吧,感觉你在强行拿 goroutine 做一个不必要的优化,“拿着锤子看什么都是钉子”系列。

关于Golang中协程(goroutine)的一个问题,很高兴为您提供一些专业见解。

协程是Go语言的一大特色,它提供了一种轻量级的方式来并发执行任务。与传统的线程相比,协程的创建和切换开销非常小,这使得Go程序能够高效地处理大量并发任务。

如果您在使用协程时遇到问题,可能是由以下几个常见原因导致的:

  1. 资源竞争与死锁:多个协程访问共享资源时,如果没有正确使用同步机制(如互斥锁、通道等),可能会导致数据竞争或死锁。使用go run -race命令可以帮助检测数据竞争问题。

  2. 协程泄漏:如果协程没有正确终止,或者主函数在协程完成前退出,可能会导致协程泄漏。确保所有协程都能正确结束,或者使用sync.WaitGroup等工具来等待协程完成。

  3. 性能瓶颈:虽然协程开销小,但大量协程同时运行也可能导致性能问题。合理使用协程数量,避免过度并发,是优化性能的关键。

  4. 错误处理:协程中的错误需要特别处理,因为协程之间没有直接的错误传播机制。通常,使用通道(channel)来传递错误或结果是一个好的做法。

针对具体问题,您可以提供更详细的代码示例或错误描述,以便进一步分析和解决。希望这些建议对您有所帮助!

回到顶部