Go 什么';“这是处理问题的最佳方式”;打开的文件太多;?
我正在构建一个爬虫程序,它获取一个URL,从中提取链接,并访问每个链接到一定的深度;在特定站点上创建路径树 我为这个爬虫程序实现并行性的方式是,我会在找到每个新的URL时立即访问它,如下所示:Go 什么';“这是处理问题的最佳方式”;打开的文件太多;?,go,concurrency,parallel-processing,Go,Concurrency,Parallel Processing,我正在构建一个爬虫程序,它获取一个URL,从中提取链接,并访问每个链接到一定的深度;在特定站点上创建路径树 我为这个爬虫程序实现并行性的方式是,我会在找到每个新的URL时立即访问它,如下所示: func main() { link := "https://example.com" wg := new(sync.WaitGroup) wg.Add(1) q := make(chan string) go deduplicate(q, wg) q
func main() {
link := "https://example.com"
wg := new(sync.WaitGroup)
wg.Add(1)
q := make(chan string)
go deduplicate(q, wg)
q <- link
wg.Wait()
}
func deduplicate(ch chan string, wg *sync.WaitGroup) {
for link := range ch {
// seen is a global variable that holds all seen URLs
if seen[link] {
wg.Done()
continue
}
seen[link] = true
go crawl(link, ch, wg)
}
}
func crawl(link string, q chan string, wg *sync.WaitGroup) {
// handle the link and create a variable "links" containing the links found inside the page
wg.Add(len(links))
for _, l := range links {
q <- l}
}
}
func main(){
链接:=”https://example.com"
wg:=新建(sync.WaitGroup)
工作组.添加(1)
q:=制造(成串)
执行重复数据消除(q、wg)
q错误套接字中引用的文件:打开的文件太多
包括线程和套接字(加载网页的http请求被刮取)。
看这个
DNS查询也很可能由于无法创建文件而失败,但是报告的错误是没有这样的主机
问题可以通过两种方式解决:
1) Increase the maximum number of open file handles
2) Limit the maximum number of concurrent `crawl` calls
1) 是最简单的解决方案,但可能并不理想,因为它只会推迟问题,直到您找到一个链接超过新限制的网站。对于linux用户,可以使用ulimit-n
设置此限制
2) 更重要的是设计问题。我们需要限制可以同时发出的http请求的数量。我对代码做了一些修改。最重要的更改是maxGoRoutines。启动值的每个刮取调用都会插入到通道中。一旦通道已满,下一个调用将阻塞,直到从通道中删除值为止通道。每次刮取调用完成时,都会从通道中删除一个值
package main
import (
"fmt"
"sync"
"time"
)
func main() {
link := "https://example.com"
wg := new(sync.WaitGroup)
wg.Add(1)
q := make(chan string)
go deduplicate(q, wg)
q <- link
fmt.Println("waiting")
wg.Wait()
}
//This is the maximum number of concurrent scraping calls running
var MaxCount = 100
var maxGoRoutines = make(chan struct{}, MaxCount)
func deduplicate(ch chan string, wg *sync.WaitGroup) {
seen := make(map[string]bool)
for link := range ch {
// seen is a global variable that holds all seen URLs
if seen[link] {
wg.Done()
continue
}
seen[link] = true
wg.Add(1)
go crawl(link, ch, wg)
}
}
func crawl(link string, q chan string, wg *sync.WaitGroup) {
//This allows us to know when all the requests are done, so that we can quit
defer wg.Done()
links := doCrawl(link)
for _, l := range links {
q <- l
}
}
func doCrawl(link string) []string {
//This limits the maximum number of concurrent scraping requests
maxGoRoutines <- struct{}{}
defer func() { <-maxGoRoutines }()
// handle the link and create a variable "links" containing the links found inside the page
time.Sleep(time.Second)
return []string{link + "a", link + "b"}
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func main(){
链接:=”https://example.com"
wg:=新建(sync.WaitGroup)
工作组.添加(1)
q:=制造(成串)
执行重复数据消除(q、wg)
q错误套接字中引用的文件:打开的文件太多
包括线程和套接字(加载网页的http请求被刮取)。
看这个
DNS查询也很可能由于无法创建文件而失败,但是报告的错误是没有这样的主机
问题可以通过两种方式解决:
1) Increase the maximum number of open file handles
2) Limit the maximum number of concurrent `crawl` calls
1) 是最简单的解决方案,但可能并不理想,因为它只会推迟问题,直到您找到一个链接超过新限制的网站。对于linux用户,可以使用ulimit-n
设置此限制
2) 更重要的是设计问题。我们需要限制可以同时发出的http请求的数量。我对代码做了一些修改。最重要的更改是maxGoRoutines。启动值的每个刮取调用都会插入到通道中。一旦通道已满,下一个调用将阻塞,直到从通道中删除值为止通道。每次刮取调用完成时,都会从通道中删除一个值
package main
import (
"fmt"
"sync"
"time"
)
func main() {
link := "https://example.com"
wg := new(sync.WaitGroup)
wg.Add(1)
q := make(chan string)
go deduplicate(q, wg)
q <- link
fmt.Println("waiting")
wg.Wait()
}
//This is the maximum number of concurrent scraping calls running
var MaxCount = 100
var maxGoRoutines = make(chan struct{}, MaxCount)
func deduplicate(ch chan string, wg *sync.WaitGroup) {
seen := make(map[string]bool)
for link := range ch {
// seen is a global variable that holds all seen URLs
if seen[link] {
wg.Done()
continue
}
seen[link] = true
wg.Add(1)
go crawl(link, ch, wg)
}
}
func crawl(link string, q chan string, wg *sync.WaitGroup) {
//This allows us to know when all the requests are done, so that we can quit
defer wg.Done()
links := doCrawl(link)
for _, l := range links {
q <- l
}
}
func doCrawl(link string) []string {
//This limits the maximum number of concurrent scraping requests
maxGoRoutines <- struct{}{}
defer func() { <-maxGoRoutines }()
// handle the link and create a variable "links" containing the links found inside the page
time.Sleep(time.Second)
return []string{link + "a", link + "b"}
}
主程序包
进口(
“fmt”
“同步”
“时间”
)
func main(){
链接:=”https://example.com"
wg:=新建(sync.WaitGroup)
工作组.添加(1)
q:=制造(成串)
执行重复数据消除(q、wg)
q您正面临一个与操作系统控制的每个用户打开的文件数限制有关的问题。如果您使用的是Linux/Unix,您可能可以使用ulimit-n 4096命令来增加限制。此命令有一个阈值,它无法设置您想要的打开文件数。因此,如果您想进一步推动它,则需要dify/etc/security/limits.conf文件,并设置硬限制和软限制。此外,您正在为您输入的每个链接启动一个goroutine,如果在某一点上有多个goroutine,则会违背goroutine的目的,实际执行任务需要更长的时间。您应该尝试使用固定数量的goroutine来执行处理和从通道读取不要为每个链接启动一个新的链接。看一看或者可能是这样的模式:?(顺便说一句,您的WaitGroup
用法非常奇怪。为每个goroutine添加1,并从每个goroutine中延迟Done
。任何其他问题都会引起bug)处理此问题的最佳方法取决于您想做什么。这是一个设计决策,而不是一个技术问题。您面临的问题与操作系统控制的每个用户打开文件的限制有关。如果您使用的是Linux/Unix,您可能可以使用ulimit-n 4096命令增加限制。此命令有一个阈值,可以“不要设置所需的打开文件的数量。因此,如果要进一步推进,则需要修改/etc/security/limits.conf文件,并设置硬限制和软限制。此外,您正在为您所编码的每个链接启动一个goroutine,并且如果在某个点上存在多个goroutine,则会违背goroutine的目的,实际需要更长的时间来完成任务。您应该尝试使用固定数量的goroutine来进行处理和从通道读取,而不是为每个链接启动一个新的goroutine。请看一看或可能是一个类似以下的模式:?(顺便说一句,您的WaitGroup
用法非常奇怪。为每个goroutine添加1,并从每个goroutine中延迟Done
。任何其他问题都会引起bug)处理它的最佳方式取决于您想做什么。这是一个设计决策,而不是一个技术问题。