Закрытие канала, когда все работники закончили - PullRequest
0 голосов
/ 07 мая 2018

Я использую веб-сканер, и у меня есть функция Parse, которая принимает ссылку в качестве входной информации и должна возвращать все ссылки, содержащиеся на странице.

Я хотел бы максимально использовать рутинные процедуры, чтобы сделать это как можно быстрее. Для этого я хочу создать пул работников.

Я установил канал строк, представляющих ссылки links := make(chan string), и передал его в качестве аргумента функции Parse. Я хочу, чтобы рабочие общались по уникальному каналу. Когда функция запускается, она берет ссылку из links, анализирует ее и ** для каждой действительной ссылки, найденной на странице, добавляет ссылку в links.

func Parse(links chan string) {
  l := <- links
  // If link already parsed, return
  for url := newUrlFounds {
    links <- url
  }
}

Тем не менее, основной проблемой здесь является указание, когда больше не было найдено ссылок. Один из способов, которым я думал об этом, - подождать, пока все рабочие не закончат. Но я не знаю, как это сделать в Go.

1 Ответ

0 голосов
/ 07 мая 2018

Как уже заметил Тим, не используйте один и тот же канал для чтения и записи на рабочем месте. Это в конечном итоге заблокирует (даже если буферизовано, потому что Мерфи).

Гораздо более простой дизайн - это просто запуск одной процедуры на URL. Буферизованный канал может служить простым семафором для ограничения числа одновременных синтаксических анализаторов (процедуры, которые ничего не делают, потому что они заблокированы, обычно пренебрежимо малы). Используйте sync.WaitGroup , чтобы дождаться завершения всей работы.

package main

import (
    "sync"
)

func main() {
    sem := make(chan struct{}, 10) // allow ten concurrent parsers
    wg := &sync.WaitGroup{}

    wg.Add(1)
    Parse("http://example.com", sem, wg)

    wg.Wait()
    // all done
}

func Parse(u string, sem chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    sem <- struct{}{}        // grab
    defer func() { <-sem }() // release

    // If URL already parsed, return.

    var newURLs []string

    // ...

    for u := range newURLs {
        wg.Add(1)
        go Parse(u)
    }
}
...