Golang Go语言中 [请教] 运行一段时间后报 goroutine 10 [chan send, 20 minutes]
Golang Go语言中 [请教] 运行一段时间后报 goroutine 10 [chan send, 20 minutes]
由于业务需要,服务器通过后台可自定义时间段轮询通过 websocket 向前端发送数据,但是运行一段时间后报错:
| goroutine 2 [chan send, 20 minutes]: |
| serve_api/internal/app/v1/service.workers.func1(0xc0001b4480, 0xc000026980, 0x12) Users/jssmac/Documents/project/golang/serve_api/internal/app/v1/service/isv.go:60 +0x63|
关键代码
//读取可查询数据列表
func GetIsvList() (interface{}, error) {
var (
newList []interface{}
list []models.LsvInfo
)
models.Find(&list, map[string]interface{}{"status": 1})
if len(list) > 0 {
//等待组完成
var wg sync.WaitGroup
//声明等待数
wg.Add(len(list))
for _, item := range list {
go func(name string) {
var c1 = worker(name)
n := <-c1
newList = append(newList, n)
wg.Done()
}(item.Item)
}
wg.Wait()
return newList, nil
} else {
return models.Array, nil
}
}
// chan
func worker(name string) chan interface{} {
out := make(chan interface{})
go func(i string) {
for {
data := getIsvInfo(i)
out <- data //原文件 isv.go:60 指向本行
}
}(name)
return out
}
//获取 ISV 数据
func getIsvInfo(name string) *Result {
urls := "http://192.168.1.188:8000/isv/"
params := url.Values{
"name": []string{name},
}
res, _ := request("GET", urls, []byte(params.Encode()))
regeo := new(Result)
json.Unmarshal(res, ®eo)
return regeo
}
//request 请求包装
func request(method, url string, data []byte) (body []byte, err error) {
if method == "GET" {
url = fmt.Sprint(url, "?", string(data))
data = nil
}
client := http.Client{Timeout: 10 * time.Second}
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
if err != nil {
return body, err
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, err = ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return body, err
}
return body, err
}
更多关于Golang Go语言中 [请教] 运行一段时间后报 goroutine 10 [chan send, 20 minutes]的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
worker 里为什么又开了一个 goroutine,而且这个 goroutine 里死循环的意义是什么,这边循环不断地写 out channel,但是外边只取了一次,第二次 send 就一直阻塞了
更多关于Golang Go语言中 [请教] 运行一段时间后报 goroutine 10 [chan send, 20 minutes]的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
worker 为什么是死循环啊?
那我不用 go func ,直接 for { data := getAspenPoint(name) out <- data } 吗?
那我这个 worker 要怎么写,能详细描述一下吗?
#3 外边调用 worker 的时候已经在一个子协程里了,里边没必要再开一个了,也不需要用一个 channel 返回结果,直接 return getIsvInfo(name)。
把 out := make(chan interface{})放到 worker(name string)里面??
好的,我试试看
go<br>func main() {<br> var (<br> sum = 100000<br> wg sync.WaitGroup<br> )<br> rs := make(chan bool, sum)<br> for i := 0; i < sum; i++ {<br> wg.Add(1)<br> go func(i int) {<br> defer wg.Done()<br> ping(rs, i, "<a target="_blank" href="http://www.baidu.com" rel="nofollow noopener">http://www.baidu.com</a>")<br> }(i)<br> }<br><br> wg.Wait()<br> close(rs)<br><br> sl := make([]interface{}, 0, sum)<br> for v := range rs {<br> sl = append(sl, v)<br> }<br><br> fmt.Println(sl)<br>}<br><br>func ping(rs chan bool, i int, urlStr string) {<br> //reqquest url<br> fmt.Println(i, urlStr)<br> <br> rs <- true<br>}<br>
模拟你的需求写了个
你的代码还有个问题,newList = append(newList, n) 这句代码在多个协程里 append newList 这个共享变量了,会有并发问题,可以把所有的结果先放入一个 channel,在 channel 的消费端统一 append 。
好的,我研究一下
好的,你看看 8 楼代码,我按照他 这种思路写?
只看错误提示,大概意思是你这个送消息到 chan 的操作,阻塞了 20 分钟了,怀疑运行时死循环你自个儿检查下。
老哥,这段代码在运行一个月后 又又又 出问题了,能帮我看看嘛
在Go语言中,看到类似 goroutine 10 [chan send, 20 minutes]
的日志输出,表明第10个goroutine在尝试向一个通道(channel)发送数据时,已经阻塞了20分钟。这通常意味着该goroutine等待的目标通道没有准备好接收数据,可能是因为:
-
接收端未启动或已停止:确保所有预期接收数据的goroutine都已正确启动,并且在发送数据前保持活跃状态。
-
缓冲区满:如果通道是有缓冲的,检查是否因为缓冲区已满而导致发送阻塞。可以考虑增加缓冲区大小,或者优化数据生产和消费的逻辑,避免生产速度远超过消费速度。
-
死锁:检查是否存在其他goroutine因某种原因也处于阻塞状态,导致整个系统陷入死锁。使用Go的race detector(通过
go run -race
)可以帮助检测数据竞争和潜在的死锁问题。 -
超时与取消:考虑实现超时机制或取消信号,使用
context.Context
来管理goroutine的生命周期和取消操作。
解决这类问题通常需要详细审查相关goroutine的启动逻辑、通道的使用方式以及数据处理流程。确保每个通道的使用都遵循了生产者-消费者模型的最佳实践,避免不必要的阻塞和死锁。如果问题复杂,可能需要逐步调试或增加日志输出,以更精确地定位问题根源。