2

我試圖像徹底的,因爲我可以在這個崗位,因爲這對我來說非常重要,使用多個HTTP requsets獲取通過parllel任務的數據檢索部分內容

雖然這個問題很簡單,只有通過閱讀這個問題的標題,你可以得到的想法......

的問題是:

與健康的帶寬(30MB VDSL)提供...

如何爲單個數據/文件獲得多個httpWebRequest

所以每個reaquest,將下載只有數據 的一部分然後當所有實例已完成,所有的部件連接回單件。

代碼:

...我已經走到這一步工作是一樣的想法只是每個任務= HttpWebRequest的=不同的文件,

所以加速是純任務並行,而一個下載使用加速多任務/線程

在我的問題。

見下面的代碼

下一部分僅僅是更詳細的explantion和背景上的主題...如果你不介意的閱讀。

,而我仍然在與此不同(有問題)一個類似的項目之一,

的方式,它

(見下面的代碼..)試圖獲取對許多不同的數據源每個分離的任務(不同的下載/文件)。 ......這樣的增速是gaind而每個(任務)不必等待前一個先完成它得到執行的機會之前。

我試圖在當前的完的問題做(具有的allmost一切都準備好下面的代碼)實際上是靶向爲相同的數據相同的URL, 所以這次獲得的加速是針對單任務 - 當前下載。

執行同樣的想法,如只是這一次下面的代碼使用多個實例,讓SmartWebClient目標相同的URL通過 。

然後(現在只有理論)它將請求部分數據內容, 與每個實例的多個請求。

最後一個問題是我需要「把puzle放回一個安寧」......另一個問題,我需要找出... ...

正如你可以在這段代碼中看到的那樣,我還沒有得到的工作是隻使用htmlAgilityPack這樣沒問題的數據解析/處理。

當前代碼

主要條目:

 var htmlDictionary = urlsForExtraction.urlsConcrDict(); 
     Parallel.ForEach(
         urlList.Values, 
         new ParallelOptions { MaxDegreeOfParallelism = 20 }, 
         url => Download(url, htmlDictionary) 
         ); 
     foreach (var pair in htmlDictionary) 
     { 
      ///Process(pair); 
      MessageBox.Show(pair.Value); 
     } 

public class urlsForExtraction 
{ 
     const string URL_Dollar= ""; 
     const string URL_UpdateUsersTimeOut=""; 


     public ConcurrentDictionary<string, string> urlsConcrDict() 
     { 
      //need to find the syntax to extract fileds names so it would be possible to iterate on each instead of specying 
      ConcurrentDictionary<string, string> retDict = new Dictionary<string,string>(); 
      retDict.TryAdd("URL_Dollar", "Any.Url.com"); 
      retDict.TryAdd("URL_UpdateUserstbl", "http://bing.com"); 
      return retDict; 
     } 


} 


/// <summary> 
/// second Stage Class consumes the Dictionary of urls for extraction 
/// then downloads Each via parallel for each using The Smart WeBClient! (download();) 
/// </summary> 
public class InitConcurentHtmDictExtrct 
{ 

    private void Download(string url, ConcurrentDictionary<string, string> htmlDictionary) 
    { 

     using (var webClient = new SmartWebClient()) 
     { 
      webClient.Encoding = Encoding.GetEncoding("UTF-8"); 
      webClient.Proxy = null; 
      htmlDictionary.TryAdd(url, webClient.DownloadString(url)); 
     } 
    } 

    private ConcurrentDictionary<string, string> htmlDictionary; 
    public ConcurrentDictionary<string, string> LoopOnUrlsVia_SmartWC(Dictionary<string, string> urlList) 
    { 

     htmlDictionary = new ConcurrentDictionary<string, string>(); 
     Parallel.ForEach(
         urlList.Values, 
         new ParallelOptions { MaxDegreeOfParallelism = 20 }, 
         url => Download(url, htmlDictionary) 
         ); 
     return htmlDictionary; 

    } 
} 
/// <summary> 
/// the Extraction Process, done via "HtmlAgility pack" 
/// easy usage to collect information within a given html Documnet via referencing elements attributes 
/// </summary> 
public class Results 
{ 
    public struct ExtracionParameters 
    { 
     public string FileNameToSave; 
     public string directoryPath; 
     public string htmlElementType; 

    } 
    public enum Extraction 
    { 
     ById, ByClassName, ByElementName 
    } 
    public void ExtractHtmlDict(ConcurrentDictionary<string, string> htmlResults, Extract By) 
    { 
     // helps with easy elements extraction from the page. 
     HtmlAttribute htAgPcAttrbs; 
     HtmlDocument HtmlAgPCDoc = new HtmlDocument(); 
     /// will hold a name+content of each documnet-part that was aventually extracted 
     /// then from this container the build of the result page will be possible 
     Dictionary<string, HtmlDocument> dictResults = new Dictionary<string, HtmlDocument>(); 

     foreach (KeyValuePair<string, string> htmlPair in htmlResults) 
     { 
      Process(htmlPair); 
     } 
    } 
    private static void Process(KeyValuePair<string, string> pair) 
    { 
     // do the html processing 
    } 

} 
public class SmartWebClient : WebClient 
{ 


    private readonly int maxConcurentConnectionCount; 

    public SmartWebClient(int maxConcurentConnectionCount = 20) 
    { 
     this.Proxy = null; 
     this.Encoding = Encoding.GetEncoding("UTF-8"); 
     this.maxConcurentConnectionCount = maxConcurentConnectionCount; 
    } 

    protected override WebRequest GetWebRequest(Uri address) 
    { 
     var httpWebRequest = (HttpWebRequest)base.GetWebRequest(address); 
     if (httpWebRequest == null) 
     { 
      return null; 
     } 

     if (maxConcurentConnectionCount != 0) 
     { 
      httpWebRequest.ServicePoint.ConnectionLimit = maxConcurentConnectionCount; 
     } 

     return httpWebRequest; 
    } 

} 
} 

這讓我好好帶寬的優勢, 只有我是遠離承受的解決方案,我會真的並欣賞就從哪裏開始任何線索。

回答

2

如果服務器支持什麼是維基百科稱byte serving,您可以複用文件下載產卵與特定Range頭值的多個請求(使用AddRange method參見How to download the data from the server discontinuously?)。大多數嚴肅的HTTP服務器都支持字節範圍。

下面是用字節範圍實現了文件的並行下載一些示例代碼:

public static void ParallelDownloadFile(string uri, string filePath, int chunkSize) 
    { 
     if (uri == null) 
      throw new ArgumentNullException("uri"); 

     // determine file size first 
     long size = GetFileSize(uri); 

     using (FileStream file = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write)) 
     { 
      file.SetLength(size); // set the length first 

      object syncObject = new object(); // synchronize file writes 
      Parallel.ForEach(LongRange(0, 1 + size/chunkSize), (start) => 
      { 
       HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 
       request.AddRange(start * chunkSize, start * chunkSize + chunkSize - 1); 
       HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

       lock (syncObject) 
       { 
        using (Stream stream = response.GetResponseStream()) 
        { 
         file.Seek(start * chunkSize, SeekOrigin.Begin); 
         stream.CopyTo(file); 
        } 
       } 
      }); 
     } 
    } 

    public static long GetFileSize(string uri) 
    { 
     if (uri == null) 
      throw new ArgumentNullException("uri"); 

     HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); 
     request.Method = "HEAD"; 
     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
     return response.ContentLength; 
    } 

    private static IEnumerable<long> LongRange(long start, long count) 
    { 
     long i = 0; 
     while (true) 
     { 
      if (i >= count) 
      { 
       yield break; 
      } 
      yield return start + i; 
      i++; 
     } 
    } 

而且樣品用量:

private static void TestParallelDownload() 
    { 
     string uri = "http://localhost/welcome.png"; 
     string fileName = Path.GetFileName(uri); 

     ParallelDownloadFile(uri, fileName, 10000); 
    } 

PS:我很好奇,想知道這是否是真的更有趣做這種並行的事情,而不是僅僅使用WebClient.DownloadFile ...也許在緩慢的網絡場景?

+0

嗨西蒙,我試圖實現'AddRange'的整個概念,但是我發現的所有代碼示例都沒有提到如何將請求/頭部/數據的範圍分割成幾部分作爲請求數組'完成後加入。通過在我的有趣的描述中說明,我請求了一個示例代碼,如果你有一點時間來創建幾行代碼,它將顯示如何使用httpWebRequest來下載分割/部分/數據部分(如果我可以使用多線程/或通過任何平行類任何可用),然後展示如何把它放回去。 – LoneXcoder

+0

@LoneXcoder - 我已經添加了一個示例。 –

+0

我不知道,還以爲它可能有效果呢造成一些(我想大多數的),您請求的服務器:說要下載的文件,只會讓u使用它們,所以如果例如帶寬帶寬的一部分每個用戶= 100kbps的,那麼多客戶端* 100kbps的應該是你的加速,在thereading方面我是不是也真的聰明一點的原因我不真的知道如果每個線程或者多任務/線程 - 爲一個你HttpWebRequest的,將導致在任何情況下都可以加快速度。我確實認爲它會有多個實例,並且部分數據paral – LoneXcoder