Вот не большой урок многопоточности в C#. Подойдёт только для простых программы. Для начала добавим элемент. У меня вот так выглядит. Почти весь код прокомментирован так что я здесь объяснять не буду. Далее добавить директивы using Code: using System; using System.Text; using System.Windows.Forms; using System.IO; using System.Net; using System.Threading; Объявим переменные Code: Thread[] threads; // Обьявляем массив потоков int i = 0; // позиция String[] lines = null; // Массив сайтов Object locks = new Object(); // Object для lock Добавим такой код на кнопку "старт". Code: lines = richTextBox1.Lines; i = 0; if (lines.Length < 1) { MessageBox.Show(this, "Слишком мало сайтов, попробуйте снова!", "Threads Example", MessageBoxButtons.OK, MessageBoxIcon.Stop); return; // завершаем если строк меньше 1 } threads = new Thread[(int)numericUpDown1.Value]; for (int q = 0; q < threads.Length; q++) { threads[q] = new Thread(main); // поток будет запускать функцию main threads[q].Start(); // запускаем } new Thread(waitth).Start(); Добавим две функций. Для отправки get запроса и ожидание завершения работы потоков. Code: private void waitth() { for (int q = 0; q < threads.Length; q++) { threads[i].Join(); // ожидаем когда потом закончится } MessageBox.Show(this, "Работа завершена!", "Threads Example", MessageBoxButtons.OK, MessageBoxIcon.Stop); } public string get(string _url, CookieCollection Cooks) // функция для отправки get запроса { try { HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(_url); webRequest.CookieContainer = new CookieContainer(); webRequest.AllowAutoRedirect = false; // автоматическая переадресация webRequest.Timeout = 30000; // время ожидания загрузки страницы webRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19"; if (Cooks != null) webRequest.CookieContainer.Add(Cooks); using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse()) { webResponse.Cookies = webRequest.CookieContainer.GetCookies(webRequest.RequestUri); if (webResponse.Cookies != null) Cooks.Add(webResponse.Cookies); string dataContent = new StreamReader(webResponse.GetResponseStream(), Encoding.GetEncoding(1251)).ReadToEnd(); string end = webResponse.Headers.ToString(); return end + dataContent; } } catch { return null; // если была ошибка в загрузке страницы возвращаем null } } На кнопку стоп Code: for (int q = 0; q < threads.Length; q++) { threads[i].Abort(); // прерываем поток } Ну и главная функция Code: private void main() { while (true) { string url; lock (locks) // доступ только с одного потока, блокирует доступ с остальных и они в процессе ожидания. { if (i > lines.Length - 1) // проверяем не весь ли массив прошли { break; // останавливаем поток } url = lines[i]; // здесь понятно i++; // всё равно что i = i +1; или i += 1; if (!url.Contains("http://")) // проверяем, если в линке нету http:// начинаем цикл заново. url.Contains("http://") == False - тоже самое { continue; // завершаем потом } } CookieCollection Cooks = new CookieCollection(); // создаём куки менеджер, автоматическии обрабатытает куки get(url, Cooks); // отправляем get запрос } } Если будут вопросы пишите, особы я не тестировал. Если что-то не так будет пишите. Скачать исходники.
Каждый раз, когда я вижу очередную "статью" на тему многопоточности, у меня возникает такое неприятное ощущение в яичках, как будто они подкатывают к горлу, вызывая одновременно тошноту и опасение, что я не сдержусь и блевану ими прямо на монитор. Уверен, это ощущение знакомо многим. И на этот раз оно меня снова не подвело. Замечательное начало статьи - wait в UI-потоке. А потом удивляемся, почему это программы на .NET такие глючные - а вот и ответ - потому что их пишут люди, начитавшиеся всяких там zoke coding style? Не, не слышал. Дам совет - именуй все переменные, функции и классы так, чтобы было удобно тебе, не думай о тех людях, которые будут потом читать твой код. Если тебе удобно писать вот так: PHP: public CTSDF_string_w45 My_csr_s234_getWHGAS_CString_R123(CTSDF_string_w45 _url123_skahndpq3_, lstCOOOKZ_SZF10_LIST PE4ENKI_BLJAD) не слушай никого, так и пиши! IDisposable? Нет, не слышал. Ты немного неправ, позволь показать тебе более корректный вариант: PHP: catch { return null; // если была ошибка в загрузке страницы, // если наступил апокалипсис // если зомби захватили мир // если путин стал президентом // да пофиг, вернем null и все дела } Круто, я еще не видел, чтобы человек объяснял, что такое блокирующая синхронизация и как ее использовать, в одну строчку. Хотя нет, один раз ко мне на собеседование пришел парень лет 30, который на просьбу рассказать что-нибудь про многопоточный код ответил: "да я вообще не сталкивался с многопоточностью, нахрен она вообще нужна-то". Сжалься над моими мозгами! Зачем, ну зачем ты создаешь пустую коллекцию и передаешь ее в параметр функции, если эта коллекция один хрен не используется?! Зато я на днях такую "особу" оттестировал, ммм... Вообще для меня статья о многопоточности, в которой нет ни слова о многопоточности (как в этой например) - символ чего-то злого, не из нашего светлого мира. Пойду-ка лучше вызову батюшку, компьютер святой водой окропить да молебен прочесть...
Честно говоря я и думал что такая реакция будет. Ты не много прав. Можешь показать как ты многопоточность делаешь?
Ключевые слова: ThreadPool, WaitHandle, Task, Parallel, CancellationToken, async/await. Все это добро прекрасно работает, держит приличную нагрузку и показывает высокий перфоманс. Чего нельзя сказать о твоем поделии.... PHP: Uri[] uris; CancellationTokenSource cancellation; void StartWork() { cancellation = new CancellationTokenSource(); var tasks = new Task[uris.Length]; var token = cancellation.Token; for(var i = 0; i < uris.Length; i++) { var uri = uris[i]; tasks[i] = Task.Factory.StartNew(() => ProcessUri(uri, Process), token); } Task.Factory.StartNew(() => { try { Task.WaitAll(tasks, token); Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("completed"))); } catch(OperationCanceledException) { Dispatcher.BeginInvoke(new Action(() => MessageBox.Show("cancelled"))); } }); } void Cancel() { cancellation.Cancel(); } void LoadUri(Uri uri, Action<string> processor) { var request = (HttpWebRequest)WebRequest.Create(uri); request.CookieContainer = new CookieContainer(); request.AllowAutoRedirect = false; request.Timeout = 30000; request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.19) Gecko/2010031422 Firefox/3.0.19"; using (var response = (HttpWebResponse)request.GetResponse()) { response.Cookies = request.CookieContainer.GetCookies(request.RequestUri); using (var stream = response.GetResponseStream()) using (var reader = new StreamReader(stream, Encoding.GetEncoding(1251))) { var dataContent = reader.ReadToEnd(); var headers = response.Headers.ToString(); processor(headers + dataContent); } } } void Process(string content) { Console.WriteLine(content); } Ты, наверно, мне не поверишь, но этот код эффективнее твоего сарая с ручной дрочкой потоков. Вообще блин я фигею - люди почему-то бегут писать о том, в чем сами толком не разобрались. Вот у тебя статья про многопоточность - где хоть пара слов о процессорных ресурсах? Где слова про блокировки (я скромно умолчу про lock-free)? Где слова про пул потоков? Где мать их слова про race conditions, про deadlocks?! А потом мы удивляемся, почему это некоторые "разработчики" на полном серьезе по каждому чиху плодят по потоку, а потом его еще и грохают руками, получая шанс просрать память? (да, Thread.Abort() вкупе с using() может просрать память, вернее, Dispose() не будет вызван) И главное, материалов-то на эту тему хоть жопой ешь, так нет... http://www.albahari.com/threading/ http://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-1-of-n http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364 http://parallelpatterns.codeplex.com/ Неужели этого всего добра, доступного в рамках одного клика по гуглу, недостаточно для самообразования? Не, серьезно, я понимаю, что твоя "статья" это суть ответ на один из вечных вопросов античата "я напесал чекер/спамер/бота/ведро-на-колесиках акак сделать чебы было с потоками памагите пжалстаа!!!!1111". Но ответ хреновый. Как и вопрос собственно.
Когда я запускал памяти много не тратилось. Мой вариант например для чекер подойдёт? Вот кстати по смейся
Само понятие "Форум" или тематического общения, подразумевает подсказки, помощь, обмен опытом, и главное поддержка друг друга. Ведь тут у всех один общий интерес. Ни для кого не секрет. что уровень знаний у всех разный. Да и вообще каждый умен по своему. Человек в данной теме. поделился тем что знает. он не пожалел на это времени, собрал все, оформил, как мог прокомментировал. Неужели так трудно подсказать, поддержать, дополнить статью. (раз уж вы так много знаете) Такое ощущение, что Вы специально сидите на форуме, ждете какую либо тему про сишарп и составляете план очередного оригинального "высера". При этом забывается один очень важный нюанс - вы говорите в обстановке полной гласности. Просто совет - будьте помягче. в "высказываниях". Человек написал может свою первую статью, пусть даже далекую от совершенства, (это пока, ну все же когда то начинали?) Вы, своими комментариями отбиваете у человека впредь писать что либо, не говоря уже о душевной травме. Хотя, что говорить. Читайте и пишите подобное дальше, через заблеванный яичками монитор. наверное это весь смысл пребывания на форуме. ЯЯЯ
Ну, лично я бы все-таки посоветовал не писать статьи, когда чувствуешь, что сам в теме не особо разбираешься. Представь - покупаешь ты книгу, читаешь, думаешь, что там все хорошо и правильно... А оказывается, что ее писал какой-то дилетант, и в итоге ты учишься говнокодить по ней. Я вот, например, хорошо в плюсах разбираюсь или в php и понимаю, что если что-то на эту тему буду писать, то будет все правильно и так, как должно быть. А вот в DirectX 11 не особо разбираюсь, и если напишу, получится говно. Поэтому никогда не буду никакой отсебятины городить про директ икс, пока как следует тему не изучу. А это небыстро.
Я с тобой полностью согласен. Увидев этот урок ( http://zhyk.org/showthread.php?t=351080 ) стало жалко пользователей zhyk'a и для них я сделал этот урок, моему знакому понравился тот урок и он предложил его на ачате опубликовать.
Ох ты ж блин... Разложу по полочкам А проблема в том, что он ничего не знает (либо знает, но не поделился). Собрал что? Thread.Start, Thread.Abort, lock без объяснения, как оно вообще работает? И нафиг это собирать? Что я и сделал сообщением выше (см. ссылки). А статью писать... да по этой теме статей просто немерено, бери и читай, у одного только Рихтера куча материалов по многопоточности. Нет, блин, пишут отсебятину. Черт возьми, человек нифига не разобравшись в теме, бросился писать статьи. Что я, скажи на милость, должен был написать? "Молодец, пиши еще! Очень полезная статья!" что ли? Я, может быть, резко высказался, но справедливо. Не знаешь - не пиши, сначала научись читать. Если я сейчас брошусь писать статью, например, по медицине - меня тоже смешают с говном, и правильно сделают. Ну а если от одного жалкого комментария на каком-то форуме человек душевную травму получит и в петлю полезет - так ему лечиться нужно, это психиатрия. А я что-то говорил про память? Тут не в памяти дело, а в числе рабочих потоков. Что произойдет, если ты поставишь например 1000 потоков? А произойдет вот что - начнется мясорубка за процессорные ресурсы. Памяти тоже кстати говоря отожрется по мегабайту за поток - итого гигабайт. Есть одна вещь, которую многие почему-то не понимают. Нет такой вещи "многопоточность для чекера", есть только "многопоточность в целом". Есть основы, которые нужно понимать - планирование потоков, синхронизация. Это база, без нее остальные знания бесполезны. Поэтому бесполезны статьи "как сделать многопоточность в чекере" - они всегда рассказывают, как запустить пару потоков, некорректным образом их прибить и только. А если есть понимание базовых вещей - тогда сразу станет ясно, что для чекера вообще не нужна явная многопоточность - там просто нечему работать в несколько потоков, основные затраты времени - это ожидание загрузки. Отсюда вывод - достаточно асинхронного кода. Только и всего. http://pastebin.com/jWsMspM1 Этот код работает в два раза быстрее тупого многопоточного варианта при меньшем числе рабочих потоков. Для полного счастья можно еще семафором ограничить число одновременных загрузок. Я не посмеялся, я обосрался. Не пости такое больше. Это кстати как раз то, о чем я говорю - какой-то идиот запостил какое-то говно, а другие это прочли и скопировали. В итоге говна во вселенной стало еще больше, а она у нас и так изрядно засранная.
Как же я люблю античат! Ответил человеку по пунктам буквально, он мне советует Спасибо, я уже прочитал. По слогам. Два раза. И еще один для верности. И даже ответил. А вот тебе ответить нечего. Поэтому я и вижу совет "почитать еще раз". Спасибо, до меня доходит с первого раза. Будет что сказать - пиши.
Bers, следует заметить, что в твоем коде тоже не все идеально. Например, отмена операции будет происходить дольше, потому что при вызове Cancel все потоки, начавшие выполнять запрос, не остановятся, пока не сделают все до конца. Я не спорю что это правильнее, просто говорю что будет дольше. Также поначалу программа будет медленно разгоняться, поскольку в ThreadPool по умолчанию потоков примерно столько же, сколько ядер. Для данного алгоритма потоков нужно гораздо больше, потому как функция LoadUri в основном ждет данных от сервера (особенно если будет прокси) и в это время можно продолжать делать новые запросы. ThreadPool конечно будет увеличивать кол-во потоков, но всего на 1 в секунду. Естественно, это все настраивается, но иногда проще работать с сырыми потоками. Также я рекомендовал бы всем вместо громоздкого HttpWebRequest использовать WebClient. Вот так выглядит функция LoadUri с его использованием: PHP: void LoadUri(string uri, Action<string> processor) { using (var web = new WebClient()) { string result = web.DownloadString(uri); processor(web.ResponseHeaders.ToString() + result); } } Мало того, у WebClient есть еще и соответствующие асинхронные методы, которые будут работать еще быстрее за счет использования I/O completion ports. Вообще не понимаю, почему все упорно вставляют везде этот HttpWebRequest.