Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оптимизация HttpWebReqeust+loop 
:(
    Опции темы
getme
Дата 1.7.2009, 21:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 80
Регистрация: 12.9.2008

Репутация: нет
Всего: -2



Здравсвуйте,
в .NET мало работал, но сегодня понадобилось написать маленькую программульку
суть:
цикл читает одну линию из файла и делает запрос к удаленному серверу (GET запрос)
строк предположительно 30 000 - 40 000

написал вот такой код

Код

private void parseTxt()
        {
            try
            {
                StreamReader  file = new StreamReader(this.namesFileName);
                string line;
                
                string regex = @"(\d+)";
                string ResponsText;
                Match m;

                HttpWebRequest Request;
                StreamReader Stream;
                HttpWebResponse Response;

                while ((line = file.ReadLine()) != null)
                {

                    Request = (HttpWebRequest)HttpWebRequest.Create("http://example.com/" + line);
                    Request.UserAgent = "Mozilla/5.0";

                    Response = (HttpWebResponse) Request.GetResponse();
                    
                    
                    Stream = new StreamReader(Response.GetResponseStream());
                    ResponsText = Stream.ReadToEnd();

                    m = Regex.Match(ResponsText, regex, RegexOptions.IgnoreCase);

                    Response.Close();
                    Stream.Close();

                    if (m.Success)
                    {
                        GroupCollection gc = m.Groups;
                        Group g = gc[1];
                        listBox1.Items.Add(line+": "+g.Value);
                    }


                }

                file.Close();
            }
            catch (Exception e )
            {
                MessageBox.Show(e.ToString());
            }
   }         


Так как опыта в C# нет, прощу немного помочь
подскажите что как лучше делать?
к примеру объекты Request/Response каждый раз создаются в цикле
можно/нужно ли их как вынести выше и переиспользовать или что-то в этом роде?

по сути нужно от этого кода получить макс. производительность.

Спасибо
PM MAIL   Вверх
mihryak
Дата 1.7.2009, 22:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



радикально улучшить, по-моему, не получится
объекты повторно использовать тоже не выйдет - заменить Url у  WebRequest нельзя
а максимальное время здесь будет уходить на веб-операции, так что остальные мелкие недочёты не играют большой роли
их несколько:
- возможно, имеет смысл прочитать весь файл сразу (File.ReadAllLines)
- часто используемый regex стоит проверять не через статический метод, а создав экземпляр с флагом Compiled (new Regex(string pattern, RegexOptions options)) и используя его
- при таком кол-ве потенциальных Match'ей стоит начала сформировать все строки, а потом разом их добавить через метод AddRange - так не будет происходиьт многократное автоувеличение размера списка (выделяется новый массив, в 2 раза больше предыдущего). список для временного хранения этих строк стоит создать с указанным колличеством записей new List<string>(count), где count предлагаю использовать равным предполагаемому кол-ву * 1.5
- строку, состоящую более чем из 2 частей, не стоит получать их суммированием, используй string.Format("{0}: {1}", line, g.Value). причина та же - ненужные выделения памяти на промежуточные варианты

но, повторюсь, большой выгоды это не даст

Это сообщение отредактировал(а) mihryak - 1.7.2009, 22:05
PM MAIL ICQ   Вверх
getme
Дата 2.7.2009, 08:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 80
Регистрация: 12.9.2008

Репутация: нет
Всего: -2



ОК
регекс заменил на
Код

Regex regex = new Regex(@"(\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

и на

Match m = regex.Match(ResponseText);

в цикле


что касается listBox1.Items.Add(line+": "+g.Value);
это просто чтобы видно было что работа исполняется, позже это уберу
когда на 100% буду уверен что все ок

а так запись будет происходить в csv файл
примерно так
Код

saveFile.WriteLine(string.Format("\"{0}\"; \"{1}\"", line, g.Value));



Теперь такой вопрос, в файле десть строк=10 запросам

почему инфа в listBox1 поступает только после того как все десять запросов выполнятся?
визуально выглядит не очень, хотелось бы наблюдать за прогрессом, т.е видеть запрос1, запрос2 и тд.

PM MAIL   Вверх
mihryak
Дата 2.7.2009, 08:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



Цитата(getme @  2.7.2009,  09:11 Найти цитируемый пост)
почему инфа в listBox1 поступает только после того как все десять запросов выполнятся?

поступает-то она сразу, но не сразу отображается, т.к. процесс активно работает
в качестве решения можно на каждой итерации (через раз, через 10, 20, 100 итераций) вызывать Application.DoEvents()
или вынести эти запросы в отдельный поток, самый простой способ -  использовать BackgroundWorker

кстати, переход на несколько потоков может серьёзно ускорить эту задачу
если есть такая возможность - то польза многократно превысит все вышеуказанные мелочи
особо много создавать не стоит, около 20 вполне хватит

Это сообщение отредактировал(а) mihryak - 2.7.2009, 10:24
PM MAIL ICQ   Вверх
getme
Дата 2.7.2009, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 80
Регистрация: 12.9.2008

Репутация: нет
Всего: -2



BackgroundWorker пока трудно разобраться с ним.

как сделать так чтобы пошел запрос и до тех пор пока он не завершится
следующий не начинался?

Если можно маленький пример.
PM MAIL   Вверх
mihryak
Дата 2.7.2009, 11:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



Цитата(getme @  2.7.2009,  11:44 Найти цитируемый пост)
как сделать так чтобы пошел запрос и до тех пор пока он не завершится
следующий не начинался?

твой код именно так и поступает
если не дробить задачу на несколько потоков, то и при текущем варианте, и при выносе всего этого кода в BackgroundWorker запросы будут выполняться строго последовательно
PM MAIL ICQ   Вверх
getme
Дата 2.7.2009, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 80
Регистрация: 12.9.2008

Репутация: нет
Всего: -2



что то я запарился немного

давай сначала smile

есть форма, кнопка запуска и листбокс на ней, в листбокс будем выводить результат последовательно, т.е прошел запрос, показали результат.

Код

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            listBox1.Items.Add("Starting..");

            doFetch fetch = new doFetch();
            Thread th = new Thread(fetch.Go);
            th.Start();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }

    //===========================================//
    public class doFetch
    {
        public string name;
        public string first_name_hits;
        public string last_name_hits;

        StreamReader readFile;
        StreamWriter saveFile;

        public void Go()
        {
            readFile = new StreamReader(@"D:\Documents and Settings\list.txt");
            saveFile = new StreamWriter(@"D:\Documents and Settings\res2.txt", true);

            string line;
            while ((line = readFile.ReadLine()) != null)
            {
                Thread t = new Thread(delegate() { Fetch(line); });
                t.Start();
                t.Join();
            }

            readFile.Close();
            saveFile.Close();
        }

        public void Fetch(string name)
        {
            // здесь делаем ГЕТ запрос
            this.name = name;
            this.first_name_hits = "232,232";
            this.last_name_hits = "343,232";

            // а теперь записываем результат
            this.doWrite(name, this.first_name_hits, this.last_name_hits);
        }

        public void doWrite(string name, string first_hits, string last_hits)
        {
            // запись в файл
            //this.listBox.Items.Add(string.Format("{0}: {1} {2}", name, this.first_name_hits, this.last_name_hits)); // вот здесь неполучается
            this.saveFile.WriteLine(string.Format("{0}: {1} {2}", name, this.first_name_hits, this.last_name_hits)); // здесь пишем в файл все ОК
        }
    }   
}



теперь думаю как добраться до listBox1 объекта с метода  doWrite.

Подскажите плс. smile

PM MAIL   Вверх
mihryak
Дата 2.7.2009, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



Цитата(getme @  2.7.2009,  16:31 Найти цитируемый пост)
Thread t = new Thread(delegate() { Fetch(line); });

это здесь лишнее - ни к чему создавать отдельный поток для получения результата фетча, если и так находимся в дополнительном потоке, так что просто вызывай Fetch

передачу строк в ListBox можно организовать несколькими способами - можно в класс Fetch передать сам экземпляр через конструктор, а можно, что выгядит более правильным, передать делегат, обрабатывающий добавление строк
стоит не забывать, что из доп. потока нельзя изменять UIные компоненты, необходимо сначала перевести выполение в тот поток, в котором они были созданы (основной), через методы контрола Invoke(синхронный) или BeginInvoke(асинхронный). выбор метода в твоём случае непринципиален
к слову, BackgroundWorker берёт на себя всю работу по переводу контектса между потоками, он считается более простым по сравнению с работой с потоками напрямую, но мне он не нравится по ряду причин

как-то так:
Код

    public delegate void AddResult(string result);

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void LetsGo()
        {
            doFetch doFetch = new doFetch(AddResult);
            ..........
        }

        private void AddResult(string result)
        {
            if (InvokeRequired)
            {
                Invoke(new AddResult(AddResult), result);
            }
            else
            {
                listBox1.Items.Add(result);
            }
        }
    }

    public class doFetch
    {
        private readonly AddResult callback;

        public doFetch(AddResult callback)
        {
            this.callback = callback;
        }

        private void Go()
        {
            ..........
            while (...)
            {
                string result = Fetch(line);
                callback(result);
            }
        }
    }


Это сообщение отредактировал(а) mihryak - 2.7.2009, 17:26
PM MAIL ICQ   Вверх
getme
Дата 2.7.2009, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 80
Регистрация: 12.9.2008

Репутация: нет
Всего: -2



все сделал, там немного по другому было, гугл помог
Вам спасибо.  smile 

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.4953 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.