如何在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();
    }
}

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM