委托是一种表示对具有特定参数列表和返回类型的方法的引用的类型。可以使用委托将方法作为参数传递给其他方法,或者异步地调用方法。
线程是一个执行单元,它可以与进程中的其他线程并发运行。可以使用线程来同时执行多个任务,或者并行化计算密集型的工作。
委托和线程之间的区别在于,委托是一种引用方法的方式,而线程是一种执行方法的方式。可以使用委托在不同的线程上调用方法,要么使用委托的 BeginInvoke 和 EndInvoke 方法,要么使用 ThreadPool 或 Task 类。
在爬虫程序中,哪一种更合适取决于具体的设计和需求。一般来说,使用委托与 ThreadPool 或 Task 比创建和管理自己的线程更高效和方便。但是,如果想要更多地控制线程的优先级、身份或生命周期,可能需要使用线程。也可能想要考虑使用 C# 5 或更高版本中的 async/await 关键字,它们使异步编程变得更容易和清晰。例如采集每天采集TOP5的新闻网站,归纳整理当天的热点新闻为案例,代码如下:
usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Net; usingSystem.Net.Http; usingSystem.Threading.Tasks; usingHtmlAgilityPack; namespaceAsyncWebCrawler{ classProgram { staticasyncTaskMain(string[] args) { varnewsSites=newList<string>() { "https://www.bbc.com/news", "https://www.cnn.com/", "https://www.nytimes.com/", "https://www.theguardian.com/international", "https://www.aljazeera.com/", }; varhttpClientHandler=newHttpClientHandler { // 亿牛云 动态转发代理IP// 爬虫加强版 IP和端口 stringproxyHost="www.16yun.cn"; stringproxyPort="31111"; // 爬虫加强版 代理验证信息stringproxyUser="16YUN"; stringproxyPass="16IP"; // 设置代理服务器 Proxy=newWebProxy(string.Format("{0}:{1}", proxyHost, proxyPort), true), UseProxy=true, Credentials=newNetworkCredential(proxyUser, proxyPass) }; varhttpClient=newHttpClient(httpClientHandler); vartasks=newList<Task<NewsSite>>(); // 开始异步采集foreach (varnewsSiteinnewsSites) { tasks.Add(CollectNewsSiteAsync(httpClient, newsSite)); } // 等待所有异步采集任务完成varresults=awaitTask.WhenAll(tasks); // 处理采集结果,整理热点标题varhotTopics=newList<string>(); foreach (varresultinresults) { hotTopics.AddRange(result.GetHotTopics()); } // 输出结果Console.WriteLine("Hot Topics:"); foreach (varhotTopicinhotTopics) { Console.WriteLine(hotTopic); } } // 异步采集新闻网站首页staticasyncTask<NewsSite>CollectNewsSiteAsync(HttpClienthttpClient, stringnewsSite) { varhtml=awaithttpClient.GetStringAsync(newsSite); vardocument=newHtmlDocument(); document.LoadHtml(html); returnnewNewsSite(newsSite, document); } // 新闻网站类classNewsSite { privatestring_url; privateHtmlDocument_document; publicNewsSite(stringurl, HtmlDocumentdocument) { _url=url; _document=document; } // 获取热点标题publicList<string>GetHotTopics() { varhotTopics=newList<string>(); varheadlineNodes=_document.DocumentNode.SelectNodes("//h2[contains(@class,'headline')]"); if (headlineNodes!=null) { foreach (varheadlineNodeinheadlineNodes) { hotTopics.Add($"{_url}: {headlineNode.InnerText}"); } } returnhotTopics; } } } }
该示例代码会采集五个新闻网站的首页,并整理当天的热点标题。采集过程是异步的,使用 async/await 关键字实现,同时使用动态转发代理IP提高采集效率。在处理采集结果时,代码会等待所有异步采集任务完成后再进行处理,以保证异步任务全部完成。