2012-01-15 14 views
6

मुझे एसईसी वेबसाइट से लगभग 2 मिलियन फाइलें डाउनलोड करने की आवश्यकता है। प्रत्येक फाइल में एक अद्वितीय यूआरएल होता है और औसत 10kb पर होता है। यह मेरा वर्तमान कार्यान्वयन है:एकाधिक फ़ाइलों को डाउनलोड करने का एक तेज़ तरीका

List<string> urls = new List<string>(); 
    // ... initialize urls ... 
    WebBrowser browser = new WebBrowser(); 
    foreach (string url in urls) 
    { 
     browser.Navigate(url); 
     while (browser.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents(); 
     StreamReader sr = new StreamReader(browser.DocumentStream); 
     StreamWriter sw = new StreamWriter(), url.Substring(url.LastIndexOf('/'))); 
     sw.Write(sr.ReadToEnd()); 
     sr.Close(); 
     sw.Close(); 
    } 

अनुमानित समय लगभग 12 दिन है ... क्या कोई तेज़ तरीका है?

संपादित करें: यह मेरा अंतिम कार्यान्वयन है:

कई धागे में
void Main(void) 
    { 
     ServicePointManager.DefaultConnectionLimit = 10000; 
     List<string> urls = new List<string>(); 
     // ... initialize urls ... 
     int retries = urls.AsParallel().WithDegreeOfParallelism(8).Sum(arg => downloadFile(arg)); 
    } 

    public int downloadFile(string url) 
    { 
     int retries = 0; 

     retry: 
     try 
     { 
      HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url); 
      webrequest.Timeout = 10000; 
      webrequest.ReadWriteTimeout = 10000; 
      webrequest.Proxy = null; 
      webrequest.KeepAlive = false; 
      webresponse = (HttpWebResponse)webrequest.GetResponse(); 

      using (Stream sr = webrequest.GetResponse().GetResponseStream()) 
      using (FileStream sw = File.Create(url.Substring(url.LastIndexOf('/')))) 
      { 
       sr.CopyTo(sw); 
      } 
     } 

     catch (Exception ee) 
     { 
      if (ee.Message != "The remote server returned an error: (404) Not Found." && ee.Message != "The remote server returned an error: (403) Forbidden.") 
      { 
       if (ee.Message.StartsWith("The operation has timed out") || ee.Message == "Unable to connect to the remote server" || ee.Message.StartsWith("The request was aborted: ") || ee.Message.StartsWith("Unable to read data from the trans­port con­nec­tion: ") || ee.Message == "The remote server returned an error: (408) Request Timeout.") retries++; 
       else MessageBox.Show(ee.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
       goto retry; 
      } 
     } 

     return retries; 
    } 
+0

क्या इन फ़ाइलों को एक संग्रह में जोड़ा जा सकता है और एक इकाई में डाउनलोड किया जा सकता है? – Oded

+0

दुर्भाग्य से नहीं। – eyaler

+0

किसी भी कारण से आप 'WebRequest' के बजाय ब्राउज़र नियंत्रण का उपयोग कर रहे हैं? – CodesInChaos

उत्तर

11

डाउनलोड निष्पादित समवर्ती बजाय क्रमिक रूप से की, और एक समझदार MaxDegreeOfParallelism अन्यथा सेट आप बहुत अधिक समकालीन अनुरोध जो एक डॉस हमले की तरह दिखाई देगा बनाने की कोशिश करेंगे:

public static void Main(string[] args) 
    { 
     var urls = new List<string>(); 
     Parallel.ForEach(
      urls, 
      new ParallelOptions{MaxDegreeOfParallelism = 10}, 
      DownloadFile); 
    } 

    public static void DownloadFile(string url) 
    { 
     using(var sr = new StreamReader(HttpWebRequest.Create(url).GetResponse().GetResponseStream())) 
     using(var sw = new StreamWriter(url.Substring(url.LastIndexOf('/')))) 
     { 
      sw.Write(sr.ReadToEnd()); 
     } 
    } 
+1

मेरे लिए बहुत संदिग्ध लग रहा है। आप एकाधिक धागे से ब्राउज़र का साझा उदाहरण उपयोग कर रहे हैं। और किसी अन्य थ्रेड से 'Application.DoEvents' को कॉल करना शायद गलत भी है। – CodesInChaos

+0

@CodeInChaos, सहमत हुए, मैंने डाउनलोड कार्यान्वयन पर विचार किए बिना समांतरता पर ध्यान केंद्रित किया। ठीक हो जाएगा .. –

+1

..now तय है, HttpWebRequest –

6

फ़ाइलें डाउनलोड करें btw, स्थानीय फ़ाइल से निपटने के समय

संपादित की केवल 7% लेता है। धागे की संख्या आपके थ्रूपुट पर निर्भर करती है। इसके अलावा, WebClient और HttpWebRequest कक्षाएं देखें। सरल नमूना:

var list = new[] 
{ 
    "http://google.com", 
    "http://yahoo.com", 
    "http://stackoverflow.com" 
}; 

var tasks = Parallel.ForEach(list, 
     s => 
     { 
      using (var client = new WebClient()) 
      { 
       Console.WriteLine("starting to download {0}", s); 
       string result = client.DownloadString((string)s); 
       Console.WriteLine("finished downloading {0}", s); 
      } 
     }); 
+1

मैक्सडिग्री ओफपार्लेलिज्म सेट करना केवल एक चीज है। ओपी 2 मिलियन फाइलों को बताता है, इसके बिना उपर्युक्त 2 लाख कार्य आइटम कतारबद्ध करेगा और सर्वर को अधिक समवर्ती अनुरोध करेगा जिससे यह अनुमति देगा और/या संभाल सकेगा। लक्ष्य सर्वर के प्रति ग्राहक अधिकतम कनेक्शन को इसे थ्रॉटल करना सबसे अच्छा है। –

5

मैं WebClient के साथ समानांतर में कई धागे का उपयोग करें। मैं अनुशंसाओं की अधिकतम डिग्री को समानांतरता की संख्या में सेट करने की अनुशंसा करता हूं, क्योंकि समानांतरता की अनिर्धारित डिग्री लंबे समय तक चलने वाले कार्यों के लिए अच्छी तरह से काम नहीं करती है। मैंने बिना किसी समस्या के मेरी परियोजनाओं में से एक में 50 समांतर डाउनलोड का उपयोग किया है, लेकिन एक व्यक्ति डाउनलोड की गति के आधार पर बहुत कम हो सकता है।

यदि आप एक ही सर्वर से समानांतर में एकाधिक फ़ाइलें डाउनलोड करते हैं, तो आप डिफ़ॉल्ट रूप से समानांतर डाउनलोड की एक छोटी संख्या (2 या 4) तक सीमित होते हैं। जबकि http मानक इतनी कम सीमा निर्दिष्ट करता है, कई सर्वर इसे लागू नहीं करते हैं। सीमा बढ़ाने के लिए ServicePointManager.DefaultConnectionLimit = 10000; का उपयोग करें।

+0

वास्तव में ServicePointManager.DefaultConnectionLimit = 10000; 2 से अधिक गति प्राप्त करने के लिए महत्वपूर्ण साबित हुआ – eyaler

संबंधित मुद्दे