我有100M的URL,需要访问这些URL,看看哪些能访问。
从CSV中读取URL,如果能访问就存入另一个CSV。
目前,我将100M的文件拆分成了20个,逐个访问。每次全部读入管道,然后由消费者去处理(测试访问能否成功),处理完的数据再存入管道,主程序从管道中读数据,写入文件,如果监测到没数据了,就结束。
目前100万个URL 大约需要2小时。(现在有1亿个)
请问如何才能更高效的处理。
package main
import (
"encoding/csv"
"fmt"
"net/http"
"os"
"time"
)
func fileWrite(filename string, content string) {
f, error := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0660)
if error != nil {
fmt.Println(error.Error())
}
defer f.Close()
f.WriteString(content)
}
func consumer(channel_in chan string, channel_out chan string) {
for domain := range channel_in {
url := "http://" + domain
client := http.Client{
Timeout: 1 * time.Second,
}
res, error := client.Get(url)
if error == nil && res.StatusCode == http.StatusOK {
channel_out <- domain + "\n"
}
}
}
const READ_PATH = "./split/16.csv"
const WRITE_PATH = "./canVisit/16.csv"
func main() {
//读文件
file, _ := os.Open(READ_PATH)
defer file.Close()
reader := csv.NewReader(file)
content, _ := reader.ReadAll()
contentLen := len(content)
//用来存整个CSV文件的数据
productChannel := make(chan string, contentLen)
//消费者会将处理好的数据放入writeChannel
writeChannel := make(chan string, contentLen)
defer close(productChannel)
//将文件内容全部放入管道
for _, row := range content {
productChannel <- row[0]
}
//消费者处理管道中的数据
for i := 0; i < 100; i++ {
go consumer(productChannel, writeChannel)
}
for {
select {
case item := <-writeChannel:
fileWrite(WRITE_PATH, item)
case <-time.After(time.Second * 10):
goto out
}
}
out:
fmt.Println("over!")
}
提个想法,可以换head请求,减少Get接收响应体的时间
另外就是可以根据域名批量排除,比如访问一个域名出现dns错误或者ssl错误、不能建立连接,就假定整个域名下都不能访问
还有超时也可以再压短一些
这样会不够准确,所以可以再开个慢速的测试线程,把第一次测试认为是有问题的url再试一次,放宽超时再允许重试