【发布时间】:2019-10-26 05:49:45
【问题描述】:
作为第一个项目,我决定编写一个简单的异步 web-scaper。我的想法是有一个任务队列和一个“解决”任务的工人池。在编写程序时遇到了问题。
以下代码挂起:
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) 应该创建一个缓冲通道。
【问题讨论】:
-
所有方法都使用值而不是指针接收器。因此,这些方法都不会对值产生任何影响 - 因为它们会更改结构的副本 - 而不是原始结构值。请参阅tour 进行复习。
-
你也在
worker中的字符串而不是你的频道。 -
而
ntasks需要一个锁才能保证 goroutine 安全。
标签: go