2016-09-22 5 views
0

У меня есть следующий код, реализующий очередь работника:Goroutines заблокирован для цикла?

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) 
} 

Запуск этого кода, используя для цикла, содержащего если заявление (или ничего внутри), скребок не печатает полученное сообщение. Блокируя с помощью функции ListenAndServe из сети/http, он печатает полученное сообщение. Блокируя использование сна в течение 1 мс, я получаю сообщение. И, добавив оператор select в цикл for, я также получаю сообщение.

Почему цикл for без оператора select не позволяет выполнять отправку сообщений в рабочих очередях и как я буду обращаться с этим. Мне нужна инструкция if в цикле for, чтобы проверить, была ли выполнена вся работа, поэтому я могу выйти из цикла и завершить программу.

Update

предложение Amd является решением этой проблемы. Вот мой обновленный код, используя sync.WaitGroup пакета основного

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") 
} 
+2

пусто 'для {}' цикл использует 100% от ядра процессора. это совсем не хорошая практика, использующая пустой. –

+1

Цикл занятости в конечном итоге блокирует всю вашу программу. (вам также не нужно выбирать, когда у вас есть только один случай) – JimB

+0

@Amd Мне нужно остановить программу от выхода до завершения всей работы. Возможно ли это сделать без цикла for. Цикл for будет постоянно проверять, пока работа не будет выполнена. –

ответ

0

Вы можете использовать sync.WaitGroup, чтобы остановить программу от выхода, пока вся работа не будет сделана.
ПРИМЕРЬТЕ 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.") 
} 
Смежные вопросы