Goroutine被for循环阻塞了吗? [英] Goroutines blocked by for loop?

查看:234
本文介绍了Goroutine被for循环阻塞了吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码实现了工作队列:

I have the following code which implements a worker queue:

package main

import (
    "fmt"
    "net/http"
    "io"
    "time"
)

var (
    linkQueue chan Link
    scraperQueue chan chan Link
)

func CycleDirectory(page int) {
    linkQueue <- Link{Name: "asd"}
}

type Link struct {
    Name string
}

func (s Scraper) Start() {
    fmt.Println("Started")
    go func() {
        for {
            s.ScraperQueue <- s.Link
            select {
            case link := <-s.Link:
                fmt.Println(fmt.Sprintf("%v", s.Id) + ": Received " + link.Name)
            case <-s.QuitChan:
                fmt.Println("Closed")
                return
            }
        }
    }()
}

func (s Scraper) Stop() {
    go func() {
        s.QuitChan <- true
    }()
}

type Scraper struct {
    Id int
    Link chan Link
    ScraperQueue chan chan Link
    QuitChan chan bool
}

func InitScraper(id int, scraperQueue chan chan Link) Scraper {
    return Scraper {
        Id: id,
        Link: make(chan Link),
        ScraperQueue: scraperQueue,
        QuitChan: make(chan bool),
    }
}

func HelloServer(w http.ResponseWriter, req *http.Request) {
    io.WriteString(w, "hello, world!\n")
}

func main() {
    linkQueue = make(chan Link, 2000)

    numScrapers := 2

    scraperQueue = make(chan chan Link, numScrapers)

    for i := 0; i < numScrapers; i++ {
        s := InitScraper(i+1, scraperQueue)
        s.Start()
    }

    go func() {
        for {
            select {
            case link := <-linkQueue:
                go func() {
                    scraper := <-scraperQueue
                    scraper <- link
                }()
            }
        }
    }()

    CycleDirectory(1)

    // time.Sleep(1 * time.Millisecond)

    for {
        // select {
        // }
    }

    // http.HandleFunc("/hello", HelloServer)

    // http.ListenAndServe(":12345", nil)
}

使用包含if语句(或内部没有内容)的for循环运行此代码,刮板不会打印收到的消息。使用net / http中的ListenAndServe函数进行阻止,它将打印收到的消息。使用睡眠阻止1毫秒,我收到了消息。然后将一条select语句放入for循环中,我也收到消息。

Running this code using a for loop containing an if statement (or nothing inside), the scraper does not print a received message. Blocking using the ListenAndServe function from net/http, it prints the received message. Blocking using sleep for 1 ms, I receive the message. And putting a select statement in the for loop, I also receive the message.

为什么没有选择语句的for循环不允许执行在工作人员队列,以及如何处理此问题。我需要在for循环中使用if语句来检查所有工作是否已经完成,以便退出循环并结束程序。

Why is the for loop without a select statement not allowing for execution of the message sending in the worker queues, and how would I go about handling this. I need an if statement in the for loop to check if all the work has been done so I can exit the loop and end the program.

更新

Amd的建议可以解决此问题。这是我使用sync.WaitGroup
包main

Amd's suggestion is a solution to this problem. Here is my updated code using sync.WaitGroup package main

import (
    "fmt"
    "sync"
)

var (
    linkQueue chan Link
    scraperQueue chan chan Link
    wg sync.WaitGroup
)

func CycleDirectory(page int) {
    wg.Add(1)
    linkQueue <- Link{Name: "asd"}
}

type Link struct {
    Name string
}

func (s Scraper) Start() {
    fmt.Println("Started")
    go func() {
        for {
            s.ScraperQueue <- s.Link
            select {
            case link := <-s.Link:
                Scrape(s.Id, link.Name)
                s.Stop()
            case <-s.QuitChan:
                fmt.Println("Closed")
                wg.Done()
                return
            }
        }
    }()
}

func (s Scraper) Stop() {
    go func() {
        s.QuitChan <- true
    }()
}

type Scraper struct {
    Id int
    Link chan Link
    ScraperQueue chan chan Link
    QuitChan chan bool
}

func Scrape(id int, name string) {
    fmt.Println(fmt.Sprintf("%v", id) + ": Received " + name)
}

func InitScraper(id int, scraperQueue chan chan Link) Scraper {
    return Scraper {
        Id: id,
        Link: make(chan Link),
        ScraperQueue: scraperQueue,
        QuitChan: make(chan bool),
    }
}

func main() {
    linkQueue = make(chan Link, 2000)

    numScrapers := 2

    scraperQueue = make(chan chan Link, numScrapers)

    for i := 0; i < numScrapers; i++ {
        s := InitScraper(i+1, scraperQueue)
        s.Start()
    }

    go func() {
        for {
            select {
            case link := <-linkQueue:
                go func() {
                    scraper := <-scraperQueue
                    scraper <- link
                }()
            }
        }
    }()

    CycleDirectory(1)

    wg.Wait()

    fmt.Println("Done")
}


推荐答案

您可以使用 sync.WaitGroup 停止程序退出,直到完成所有工作。

围棋场

You may use sync.WaitGroup to stop the program from exiting until all the work is done.
Try it on The Go Playground:

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    wg sync.WaitGroup
)

func main() {
    wg.Add(1)
    go func() {
        defer wg.Done()
        time.Sleep(2 * time.Second)
    }()

    fmt.Println("Wait...")
    wg.Wait()
    fmt.Println("Done.")
}

这篇关于Goroutine被for循环阻塞了吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆