В качестве первого проекта я решил написать простой асинхронный веб-скейпер. Моя идея состоит в том, чтобы иметь очередь задач и пул работников, «решающих» задачи. При написании программы я столкнулся с проблемой.
висит следующий код:
package main
import (
"fmt"
"net/http"
"time"
)
type Scraper struct {
client http.Client
timeout int
tasks chan string
results chan int
ntasks int
}
func (s Scraper) Init(timeout int, workers int) {
s.client = http.Client{
Timeout: time.Second * time.Duration(timeout),
}
s.timeout = timeout
s.ntasks = 0
s.Dispatch(workers)
}
func (s Scraper) Wait() {
for i := 0; i < s.ntasks; i++ {
<-s.results
}
}
func (s Scraper) Task(task string) {
s.tasks <- task // hangs on this line
s.ntasks++;
}
func (s Scraper) Dispatch(workers int) {
s.tasks = make(chan string, 100)
s.results = make(chan int, 100)
for i := 0; i < workers; i++ {
go s.worker(i)
}
}
func (s Scraper) worker(id int) {
for task := range <-s.tasks {
fmt.Println(task)
s.results <- 0
}
}
func main() {
s := Scraper{}
s.Init(10, 5)
s.Task("Hello World")
s.Wait()
}
пока это не так:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "started job", j)
time.Sleep(time.Second)
fmt.Println("worker", id, "finished job", j)
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 5; a++ {
<-results
}
}
Глядя на переполнение стека, я увидел, что небуферизованные каналы зависли, но make (chan string, 100) должна создать буферизованный.