这段协程怎么不阻塞?

程序片段如下:

runtime.GOMAXPROCS(runtime.NumCPU())
        //maxPage := getMaxPage()
        maxPage := 10
        if maxPage > 0 {
            jobs := make(chan int, maxPage)
            results := make(chan []map[string]string, maxPage)

            // 招聘工人,让他们工作(待命),每个工人会从jobs管道里获得任务,工人干活,把结果放到results管道
            for w := 1; w <= runtime.NumCPU(); w++ {
                go worker(w, jobs, results)
            }
            db, err := mysqlUtil.CreateReadDb()
            if err != nil {
                log.Fatal("connect db err ", err)
                fmt.Println("connect db err ", err)
            }

            //分配任务
            for j := 1; j <= maxPage; j++ {
                jobs <- j
            }
            close(jobs)
            for data := range results {
                //写数据库操作
            }
            close(results)
            fmt.Println("all done...")
        }

woker函数如下:

func worker(id int, jobs <-chan int, results chan<- []map[string]string) {
    for j := range jobs {
        url := host + "/type/1/" + strconv.Itoa(j) + ".html"
        fmt.Println()
        data := getData(url)
        fmt.Printf("worker %d finished job %d", id, j)
        fmt.Println()
        results <- data
    }
}

现在的问题是程序在

for data := range results {
                //写数据库操作
            }

这一个地方阻塞住了,job都完成了,job完成后的数据都放到了result里面,上面也都完成了写库操作,为啥阻塞在了那里,不往下执行了呢?

阅读 2.6k
3 个回答

range results 这个操作只有在关闭管道之后,才会继续往下执行。否则会一直阻塞。

            for j := 1; j <= maxPage; j++ {
                data := <- results
                //写数据库
                fmt.Println(len(data))
            }
            close(results)

程序有点问题,处理结果这样操作就行了,就不会阻塞了。

go func(){
        for data := range results {
            //写数据库操作
        }
    }()
    

把这个放goruntine即可。另外还要注意控制主进程退出的时机,防止goruntine没处理完主进程就退出。
阻塞的原因是results在缓存为空的时候会阻塞除非results被close,你这里主进程被阻塞了,一直跑不到close的地方。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题