Здравствуйте. Учу C#. Надо: 1. загрузить веб-страницу (делаю через WebBrowser) 2. вытащить из html-кода адреса всех изображений (беру через Document.Images, ложу в HtmlElementCollection и выдергиваю адреса через GetAttribute("src") в foreach) 3. загрузить все изображения на локальный компьютер, запустив загрузку каждого в отдельном потоке Проблемы с 3 пунктом. На странице 5 изображений, но они не грузятся, в нужной папке образуется 2-4 файла, иногда пустых (5 ни разу не было), иногда (не всегда) вылезает сообщение об ошибке COM: Code: An unhandled exception of type 'System.Runtime.InteropServices.InvalidComObjectException' occurred in System.Windows.Forms.dll Additional information: COM object that has been separated from its underlying RCW cannot be used. Изначально в коде было DownloadFileAsync, после замены на просто DownloadFile опять стала нерегулярно вылетать ошибка COM, также теперь прут ошибки о невозможности доступа к файлу (файл занят другим процессом), но не для всех файлов и потоков такое, а только для 2-3 (из 5). Остальные файлы скачиваются нормально или пустые. Код: Code: static void Main() { Thread.CurrentThread.Name = "main_thread"; try { thrcnt = 0; imgwork(); } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error: {0}",ex); Console.ForegroundColor = ConsoleColor.White; Console.ReadLine(); }; } static HtmlElementCollection loadwork() { //тут первые 2 пункта, выполняются нормально } static void imgwork() { HtmlElementCollection allimg = loadwork(); foreach (HtmlElement cimg in allimg) { Random rndm = new Random(); try { Thread thr = new Thread(delegate() { loadimg(cimg.GetAttribute("src"), string.Concat("C:\\csh\\", rndm.Next(0, 1024).ToString(), ".gif")); }); thrcnt++; thr.Name = thrcnt.ToString(); Console.WriteLine("Starting thread {0}...", thr.Name.ToString()); thr.Start(); if (thr.ThreadState == ThreadState.Running) Console.WriteLine("Thread {0} started!", thr.Name.ToString()); else throw new Exception("Thread error!"); thr = null; Console.WriteLine("Loading {0}...", cimg.GetAttribute("src")); } catch (System.Runtime.InteropServices.InvalidComObjectException comex) { Console.WriteLine(comex); } } } static void loadimg(string img_url, string save_path) { Console.WriteLine("Thread {1}: Downloading {0}...", img_url, Thread.CurrentThread.Name.ToString()); WebClient wcl = new WebClient(); Uri url = new Uri(img_url); try { wcl.DownloadFile(url, save_path); } catch (System.Net.WebException wex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error: {0}", wex); } Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("{0}: wcl.DownloadFile begin...", Thread.CurrentThread.Name.ToString()); wcl.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wcl_DownloadFileCompleted); } lock пробовал ставить буквально на всё, не помогает. Прошу помощи, бьюсь уже третий день.
первую ошибку вижу в рандомных именах. дело в том, что числа могут повторятся, при этом возникает конфликт.
Вот мой пример может тебе поможет! День добрый, если ещё нужно, попробуй вот этот код, ему конечно далеко до совершенства, но... у меня просто задача практически идентична твоей...и у меня это работает, давольно не плохо... Code: static int CountThread = Program.countThread; Thread[] t = new Thread[CountThread]; Thread Control; public int timerwhile = 0; static object locker = new object(); delegate void SetTextCallback(string text); public int countB = 0; public int state = 0; //для доступа к элементам из потока!!! private void SetText(string text) { if (this.label5.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); label5.Text = text; } else { label5.Text = text; } } //****************************************** private void button1_Click(object sender, EventArgs e) { progressBar1.Maximum = getFullCountShpiWithNull(); label4.Text = progressBar1.Maximum.ToString(); timer1.Enabled = true; Control = new Thread(Start); Control.Start(); } private void Start() { while (timerwhile == 0) { for (int i = 0; i < CountThread; i++) { if (t[i] == null) { t[i] = new Thread(Start1); t[i].Name = "Im-" + i.ToString(); t[i].Start(); } else { if (t[i].ThreadState == ThreadState.Aborted) { t[i].Abort(); t[i] = new Thread(Start1); t[i].Name = "Im-" + i.ToString(); t[i].Start(); } if( (t[i].ThreadState == ThreadState.Stopped)) { t[i] = new Thread(Start1); t[i].Name = "Im-" + i.ToString(); t[i].Start(); } } } } } private void Start1() { // Thread.CurrentThread.Join(1000); lock (locker) { getState(getShpiFromBase()); } // Thread.CurrentThread.Join(1000); } private void button2_Click(object sender, EventArgs e) { for (int i = 0; i < CountThread; i++) { if (t[i] != null) { t[i].Abort(); } } if (Control != null) { Control.Abort(); } } private void getState(object shpi) { string[] barcode = (string[])shpi; string str = ""; string st1 = ""; string st2 = ""; int a, b, c; for (int d = 0; d < barcode.Length; d++) { SetText((d + 1).ToString()); SetText2(d + 1); try { if ((barcode[d] != null) && (barcode[d] != "")) { WebRequest request = HttpWebRequest.Create(Program.strWebReq + barcode[d]); /* if (Program.webpr.Address.AbsolutePath != "") { request.Proxy = Program.webpr; }*/ /* if (webproxy.UseProxy().Address.AbsoluteUri != "") { request.Proxy = webproxy.UseProxy(); }*/ request.Method = "POST"; request.Timeout = 1000*Program.TimeReqWeb; WebResponse response = request.GetResponse(); StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(1251)); } catch (Exception ex) { SaveLogs.SaveLogInFile(DateTime.Now.ToString() + " " + ex.ToString() + "\r\n"); } //Exit } countB = 0; a = progressBar1.Maximum; b = getFullCountShpiWithNull(); c = a - b; SetText3(c); SetText2(0); }
Тоже хотел посоветовать использовать WebRequest и дергать картинки RegExp; gudus, зачем HttpWebRequest?
Просто я так привык..., у меня задача другая... да и я просто хотел показать как я реализовал вопрос с потоками...у меня работает на ура!!! вот только я чего-то не понимаю, люди тут пишут что хотят в 50-т потоков программы запускать,,,,, , насколько я слышал, 2-а потока на одно ядро....)) не более...а иначе смысла нет... очередь.. вопрос: а имеет ли смысл делать в программе 50-т потоков если у меня 4-е ядра..??=))
Есть смысл, если тебе надо выполнить некоторый блок, в котором предусматривается задержка, и он циклический. Core i7 топовый поддерживает 12 потоков (2 потока на каждое из 6ти ядер) одновременно выполняющихся
Имеет. У тебя при скачивании поток останавливается и ждет данные, при этом освобождая процессор для остальных.
А в чём разница??? я просто не много не пойму??? у меня также получается... запускаю потоки, и они выполняю асинхронно запросы, единственное ограничение железа и канала, по мимо этого есть есть основной и контролирующий, чтобы не дать разрастись...и вроде как на тестах красоту показывает...,!
Я сам только начал программировать. На RSDN попросил прокритиковать код и мне посоветовали либо использовать асинхронные запросы, либо пул потоков. В общем это один из паттернов.
Помни, об этом стоит начинать беспокоиться если при работе твоего софта проц загружен на 100%, не раньше Не надо что-то чинить если оно и так работает.