如何在http请求中使用线程池(干货)

这段时间对网络爬虫比较感兴趣,实现起来实际上比较简单。无非就是http的web请求,然后对返回的html内容进行内容筛选。本文的重点不在于这里,而在于多线程做http请求。例如我要实现如下场景:我有N个对象集合,需要通过http的方式获取每个对象的相关信息。废话不多说,直接上代码

实现方式一:依次循环遍历对象集合,这种方式最为普通

for (int i = ; i < videoInfoList.Count; i++)
{
//普通方式
directRun(videoInfoList[i]);
} private void directRun(VideoInfo item)
{
var htmlStr = GetHtmlCode(item.url);
item.name= getName(htmlStr);
videoInfoQueue.Enqueue(item);
} private static string GetHtmlCode(string url)
{
string htmlCode;
HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
webRequest.Timeout = ;
webRequest.Method = "GET";
webRequest.UserAgent = "Mozilla/4.0";
webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
try
{
HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();
using (System.IO.Stream streamReceive = webResponse.GetResponseStream())
{
using (var zipStream = new System.IO.Compression.GZipStream(streamReceive, System.IO.Compression.CompressionMode.Decompress))
{
using (StreamReader sr = new System.IO.StreamReader(zipStream, Encoding.UTF8))
{
htmlCode = sr.ReadToEnd();
}
}
}
}
catch
{
return null;
}
finally
{
// 释放资源
webRequest.Abort();
}
return htmlCode;
}

实现方式二:使用线程池,使用异步多线程的方式提高效率

在使用线程池的时候一定要注意设置ServicePointManager.DefaultConnectionLimit, 因为默认不设置是2,会导致同时的http请求只能是2个,因为这个问题我自己也卡了很久。使用队列管理,启动一个定时器线程,实时刷新显示获取到的数 据。实际的开发中,队列和线程池往往是一对组合出现。至于入队时候使用锁的问题,这里可以使用volatile也可以直接使用object锁,防止入队出错

//已经入队的数目
private int loadingNum = ;
//总数目
private int importNum = ;
//定义队列
private Queue<VideoInfo> videoInfoQueue = new Queue<VideoInfo>();
//锁
private object sb = new object(); ServicePointManager.DefaultConnectionLimit = ;
for (int i = ; i < videoInfoList.Count; i++)
{
//多线程
ThreadPool.QueueUserWorkItem(multithreadingRun, videoInfoList[i]);
Thread.Sleep();
} private void multithreadingRun(object o)
{
VideoInfo item = o as VideoInfo;
var htmlStr = GetHtmlCode(item.url);
item.name = getName(htmlStr);
//使用锁入队
lock (sb)
{
videoInfoQueue.Enqueue(item);
}
} //使用定时器进行出队显示
private void Timer1_Tick(object sender, EventArgs e)
{
if (videoInfoQueue.Count > )
{
VideoInfo item = videoInfoQueue.Dequeue();
label1.Text ++= item.name;
}
if (loadingNum == importNum)
{
timer1.Stop();
}
}

至此,结束,本文也是我的第一篇博文,欢迎指教!

上一篇:BZOJ 3127 [Usaco2013 Open]Yin and Yang(树点分治)


下一篇:WPF、WinForm(C#)多线程编程并更新界面(UI)(转载积累)