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

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

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

for (int i = 0; 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 = 10000;
    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 = 0;
//总数目
private int importNum = 0;
//定义队列
private Queue<VideoInfo> videoInfoQueue = new Queue<VideoInfo>();
//
private object sb = new object();


ServicePointManager.DefaultConnectionLimit = 20;
for (int i = 0; i < videoInfoList.Count; i++)
{
    //多线程
    ThreadPool.QueueUserWorkItem(multithreadingRun, videoInfoList[i]);
    Thread.Sleep(1);
}

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 > 0)
    {
        VideoInfo item = videoInfoQueue.Dequeue();
        label1.Text ++= item.name;
    }
    if (loadingNum == importNum)
    {
        timer1.Stop();
    }
}

 

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

 

posted @ 2018-01-27 09:52  colorfulCat  阅读(3293)  评论(0编辑  收藏  举报